Merge branch 'work'
authorMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 15 Jan 2006 23:01:27 +0000 (21:01 -0200)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 15 Jan 2006 23:01:27 +0000 (21:01 -0200)
957 files changed:
Documentation/SubmittingDrivers
Documentation/SubmittingPatches
Documentation/feature-removal-schedule.txt
Documentation/filesystems/tmpfs.txt
Documentation/kernel-parameters.txt
Documentation/scsi/aacraid.txt [new file with mode: 0644]
Documentation/spi/butterfly [new file with mode: 0644]
Documentation/spi/spi-summary [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/common/Kconfig
arch/arm/common/Makefile
arch/arm/common/locomo.c
arch/arm/common/sa1111.c
arch/arm/common/vic.c [new file with mode: 0644]
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/calls.S
arch/arm/kernel/ecard.c
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/entry-header.S
arch/arm/kernel/head.S
arch/arm/kernel/ptrace.c
arch/arm/kernel/semaphore.c
arch/arm/kernel/sys_arm.c
arch/arm/kernel/sys_oabi-compat.c [new file with mode: 0644]
arch/arm/kernel/traps.c
arch/arm/lib/ashldi3.S
arch/arm/lib/ashrdi3.S
arch/arm/lib/lib1funcs.S
arch/arm/lib/lshrdi3.S
arch/arm/lib/muldi3.S
arch/arm/lib/ucmpdi2.S
arch/arm/mach-aaec2000/aaed2000.c
arch/arm/mach-at91rm9200/board-csb337.c
arch/arm/mach-at91rm9200/board-csb637.c
arch/arm/mach-at91rm9200/board-dk.c
arch/arm/mach-at91rm9200/board-ek.c
arch/arm/mach-clps711x/autcpu12.c
arch/arm/mach-clps711x/cdb89712.c
arch/arm/mach-clps711x/ceiva.c
arch/arm/mach-clps711x/clep7312.c
arch/arm/mach-clps711x/edb7211-arch.c
arch/arm/mach-clps711x/fortunet.c
arch/arm/mach-clps711x/p720t.c
arch/arm/mach-clps7500/core.c
arch/arm/mach-ebsa110/core.c
arch/arm/mach-footbridge/cats-hw.c
arch/arm/mach-footbridge/co285.c
arch/arm/mach-footbridge/ebsa285.c
arch/arm/mach-footbridge/netwinder-hw.c
arch/arm/mach-footbridge/personal.c
arch/arm/mach-h720x/h7201-eval.c
arch/arm/mach-h720x/h7202-eval.c
arch/arm/mach-imx/mx1ads.c
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-integrator/lm.c
arch/arm/mach-iop3xx/iop321-setup.c
arch/arm/mach-iop3xx/iop331-setup.c
arch/arm/mach-ixp2000/core.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x01.c
arch/arm/mach-ixp4xx/coyote-setup.c
arch/arm/mach-ixp4xx/gtwx5715-setup.c
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-ixp4xx/nas100d-setup.c
arch/arm/mach-ixp4xx/nslu2-setup.c
arch/arm/mach-l7200/core.c
arch/arm/mach-lh7a40x/arch-kev7a400.c
arch/arm/mach-lh7a40x/arch-lpd7a40x.c
arch/arm/mach-omap1/board-generic.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-netstar.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/board-voiceblue.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-realview/Kconfig
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mach-s3c2410/mach-anubis.c
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-h1940.c
arch/arm/mach-s3c2410/mach-n30.c
arch/arm/mach-s3c2410/mach-nexcoder.c
arch/arm/mach-s3c2410/mach-otom.c
arch/arm/mach-s3c2410/mach-rx3715.c
arch/arm/mach-s3c2410/mach-smdk2410.c
arch/arm/mach-s3c2410/mach-smdk2440.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/h3600.c
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/jornada720.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-shark/core.c
arch/arm/mach-versatile/Kconfig
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/versatile_ab.c
arch/arm/mach-versatile/versatile_pb.c
arch/arm/nwfpe/fpa11.h
arch/arm/plat-omap/Kconfig
arch/i386/Kconfig
arch/i386/Makefile
arch/i386/kernel/traps.c
arch/i386/pci/fixup.c
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/sn2_defconfig
arch/ia64/hp/sim/simserial.c
arch/ia64/kernel/fsys.S
arch/ia64/kernel/jprobes.S
arch/ia64/kernel/kprobes.c
arch/ia64/kernel/mca_asm.S
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/traps.c
arch/ia64/mm/tlb.c
arch/ia64/sn/include/xtalk/hubdev.h
arch/ia64/sn/kernel/bte_error.c
arch/ia64/sn/kernel/huberror.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/tiocx.c
arch/ia64/sn/kernel/xpc.h [deleted file]
arch/ia64/sn/kernel/xpc_channel.c
arch/ia64/sn/kernel/xpc_main.c
arch/ia64/sn/kernel/xpc_partition.c
arch/ia64/sn/pci/pcibr/pcibr_dma.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/parisc/kernel/drivers.c
arch/powerpc/Kconfig
arch/powerpc/Makefile
arch/powerpc/boot/Makefile
arch/powerpc/boot/crt0.S
arch/powerpc/boot/dummy.c [new file with mode: 0644]
arch/powerpc/boot/hack-coff.c [new file with mode: 0644]
arch/powerpc/boot/main.c
arch/powerpc/boot/prom.c
arch/powerpc/boot/prom.h
arch/powerpc/boot/rs6000.h [new file with mode: 0644]
arch/powerpc/boot/stdio.c [new file with mode: 0644]
arch/powerpc/boot/stdio.h
arch/powerpc/boot/string.S
arch/powerpc/boot/zImage.coff.lds [new file with mode: 0644]
arch/powerpc/configs/mpc834x_sys_defconfig [new file with mode: 0644]
arch/powerpc/configs/pmac32_defconfig
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cpu_setup_power4.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/fpu.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/idle_power4.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci_32.c [new file with mode: 0644]
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_parse.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/vio.c
arch/powerpc/lib/locks.c
arch/powerpc/oprofile/common.c
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/mpc834x_sys.c [new file with mode: 0644]
arch/powerpc/platforms/83xx/mpc834x_sys.h [new file with mode: 0644]
arch/powerpc/platforms/83xx/mpc83xx.h [new file with mode: 0644]
arch/powerpc/platforms/83xx/pci.c [new file with mode: 0644]
arch/powerpc/platforms/chrp/pci.c
arch/powerpc/platforms/chrp/setup.c
arch/powerpc/platforms/chrp/time.c
arch/powerpc/platforms/iseries/irq.c
arch/powerpc/platforms/iseries/misc.S
arch/powerpc/platforms/iseries/setup.c
arch/powerpc/platforms/iseries/smp.c
arch/powerpc/platforms/maple/pci.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/maple/time.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/fsl_soc.c [new file with mode: 0644]
arch/powerpc/sysdev/fsl_soc.h [new file with mode: 0644]
arch/ppc/4xx_io/serial_sicc.c
arch/ppc/Kconfig
arch/ppc/boot/Makefile
arch/ppc/boot/openfirmware/Makefile
arch/ppc/boot/openfirmware/coffmain.c [deleted file]
arch/ppc/boot/openfirmware/newworldmain.c [deleted file]
arch/ppc/kernel/Makefile
arch/ppc/kernel/head_8xx.S
arch/ppc/kernel/misc.S
arch/ppc/kernel/pci.c
arch/ppc/kernel/ppc_ksyms.c
arch/ppc/kernel/setup.c
arch/ppc/kernel/traps.c
arch/ppc/mm/init.c
arch/ppc/platforms/83xx/mpc834x_sys.c
arch/ppc/platforms/85xx/mpc8540_ads.c
arch/ppc/platforms/85xx/mpc8560_ads.c
arch/ppc/platforms/85xx/mpc85xx_cds_common.c
arch/ppc/platforms/85xx/sbc8560.c
arch/ppc/platforms/85xx/stx_gp3.c
arch/ppc/platforms/85xx/tqm85xx.c
arch/ppc/platforms/Makefile
arch/ppc/platforms/chrp_pci.c
arch/ppc/platforms/chrp_setup.c
arch/ppc/platforms/chrp_time.c
arch/ppc/platforms/pmac_backlight.c [deleted file]
arch/ppc/platforms/pmac_cache.S [deleted file]
arch/ppc/platforms/pmac_cpufreq.c [deleted file]
arch/ppc/platforms/pmac_feature.c [deleted file]
arch/ppc/platforms/pmac_low_i2c.c [deleted file]
arch/ppc/platforms/pmac_nvram.c [deleted file]
arch/ppc/platforms/pmac_pci.c [deleted file]
arch/ppc/platforms/pmac_pic.c [deleted file]
arch/ppc/platforms/pmac_pic.h [deleted file]
arch/ppc/platforms/pmac_setup.c [deleted file]
arch/ppc/platforms/pmac_sleep.S [deleted file]
arch/ppc/platforms/pmac_smp.c [deleted file]
arch/ppc/platforms/pmac_time.c [deleted file]
arch/ppc/syslib/Makefile
arch/ppc/syslib/mpc83xx_devices.c
arch/ppc/syslib/mpc85xx_devices.c
arch/ppc/syslib/ocp.c
arch/ppc/syslib/prom.c
arch/ppc/xmon/start.c
arch/ppc/xmon/xmon.c
arch/s390/crypto/aes_s390.c
arch/s390/crypto/des_s390.c
arch/s390/crypto/sha256_s390.c
arch/s390/kernel/process.c
arch/s390/kernel/setup.c
arch/s390/kernel/time.c
arch/s390/kernel/vtime.c
arch/s390/lib/Makefile
arch/s390/lib/spinlock.c
arch/sh/kernel/cpu/bus.c
arch/um/Makefile
block/genhd.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/ec.c
drivers/base/dd.c
drivers/base/driver.c
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/base/power/shutdown.c
drivers/block/loop.c
drivers/block/pktcdvd.c
drivers/bluetooth/hci_bcsp.c
drivers/char/amiserial.c
drivers/char/drm/r128_state.c
drivers/char/esp.c
drivers/char/generic_serial.c
drivers/char/riscom8.c
drivers/char/serial167.c
drivers/char/specialix.c
drivers/char/synclink.c
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Makefile
drivers/char/watchdog/mpc83xx_wdt.c [new file with mode: 0644]
drivers/char/watchdog/sa1100_wdt.c
drivers/char/watchdog/sbc_epx_c3.c [new file with mode: 0644]
drivers/cpufreq/cpufreq.c
drivers/dio/dio-driver.c
drivers/firmware/dell_rbu.c
drivers/i2c/i2c-core.c
drivers/ide/ide-cd.c
drivers/ide/ide-disk.c
drivers/ide/ide-floppy.c
drivers/ide/ide-tape.c
drivers/ide/ide-taskfile.c
drivers/ide/ide.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/device.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/core/ucm.c
drivers/infiniband/core/uverbs.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/mthca/mthca_av.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_dev.h
drivers/infiniband/hw/mthca/mthca_eq.c
drivers/infiniband/hw/mthca/mthca_provider.c
drivers/infiniband/hw/mthca/mthca_qp.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/infiniband/ulp/ipoib/ipoib_verbs.c
drivers/infiniband/ulp/ipoib/ipoib_vlan.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/input/gameport/gameport.c
drivers/input/input.c
drivers/input/mouse/alps.c
drivers/input/mouse/logips2pp.c
drivers/input/mouse/psmouse-base.c
drivers/input/mouse/psmouse.h
drivers/input/mouse/synaptics.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/serio.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c [new file with mode: 0644]
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/hscx_irq.c
drivers/isdn/hisax/jade_irq.c
drivers/macintosh/macio-adb.c
drivers/macintosh/macio_asic.c
drivers/md/bitmap.c
drivers/md/dm-crypt.c
drivers/md/dm-ioctl.c
drivers/md/dm-snap.c
drivers/md/dm.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/md/raid6main.c
drivers/media/dvb/bt8xx/dvb-bt8xx.c
drivers/media/video/bttv-gpio.c
drivers/media/video/bttv.h
drivers/media/video/tvp5150.c
drivers/media/video/zoran_card.c
drivers/message/fusion/Kconfig
drivers/message/fusion/lsi/mpi.h
drivers/message/fusion/lsi/mpi_cnfg.h
drivers/message/fusion/lsi/mpi_history.txt
drivers/message/fusion/lsi/mpi_init.h
drivers/message/fusion/lsi/mpi_ioc.h
drivers/message/fusion/lsi/mpi_log_fc.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_log_sas.h [new file with mode: 0644]
drivers/message/fusion/lsi/mpi_sas.h
drivers/message/fusion/mptbase.c
drivers/message/fusion/mptbase.h
drivers/message/fusion/mptctl.c
drivers/message/fusion/mptfc.c
drivers/message/fusion/mptlan.c
drivers/message/fusion/mptsas.c
drivers/message/fusion/mptscsih.c
drivers/message/fusion/mptspi.c
drivers/message/i2o/pci.c
drivers/mfd/mcp-core.c
drivers/mmc/mmc_block.c
drivers/mmc/mmc_sysfs.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/doc2000.c
drivers/mtd/devices/doc2001.c
drivers/mtd/devices/doc2001plus.c
drivers/mtd/devices/m25p80.c [new file with mode: 0644]
drivers/mtd/devices/mtd_dataflash.c [new file with mode: 0644]
drivers/mtd/nand/diskonchip.c
drivers/net/Kconfig
drivers/net/cs89x0.c
drivers/net/e100.c
drivers/net/sb1000.c
drivers/net/wireless/hostap/hostap_80211_rx.c
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/ipw2100.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/wavelan.c
drivers/pci/pci-driver.c
drivers/pcmcia/ds.c
drivers/pnp/driver.c
drivers/rapidio/rio-driver.c
drivers/s390/block/dasd.c
drivers/s390/cio/airq.c
drivers/s390/cio/blacklist.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_id.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/device_pgid.c
drivers/s390/cio/device_status.c
drivers/s390/cio/qdio.c
drivers/s390/net/ctcmain.c
drivers/s390/net/cu3088.c
drivers/s390/net/netiucv.c
drivers/s390/s390_rdev.c
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/scsi/zfcp_sysfs_adapter.c
drivers/s390/scsi/zfcp_sysfs_port.c
drivers/s390/scsi/zfcp_sysfs_unit.c
drivers/sbus/char/aurora.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-9xxx.h
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h
drivers/scsi/BusLogic.c
drivers/scsi/Makefile
drivers/scsi/aacraid/README [deleted file]
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commctrl.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aic7xxx/Kconfig.aic7xxx
drivers/scsi/aic7xxx/aic79xx.h
drivers/scsi/aic7xxx/aic79xx.reg
drivers/scsi/aic7xxx/aic79xx.seq
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/aic7xxx/aic79xx_inline.h
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic79xx_osm.h
drivers/scsi/aic7xxx/aic79xx_pci.c
drivers/scsi/aic7xxx/aic79xx_pci.h
drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/aic7xxx/aic7xxx_osm.h
drivers/scsi/aic7xxx/aic7xxx_pci.c
drivers/scsi/aic7xxx/aic7xxx_pci.h
drivers/scsi/aic7xxx_old.c
drivers/scsi/ch.c
drivers/scsi/dpt_i2o.c
drivers/scsi/hosts.c
drivers/scsi/ips.c
drivers/scsi/iscsi_tcp.c
drivers/scsi/iscsi_tcp.h
drivers/scsi/libata-core.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/megaraid/megaraid_mbox.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/scsi/qla2xxx/Kconfig
drivers/scsi/qla2xxx/Makefile
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_dbg.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/raid_class.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_priv.h
drivers/scsi/scsi_proc.c
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/scsi/scsi_transport_fc.c
drivers/scsi/scsi_transport_iscsi.c
drivers/scsi/scsi_transport_sas.c
drivers/scsi/scsi_transport_spi.c
drivers/scsi/sd.c
drivers/scsi/sr.c
drivers/scsi/sr_ioctl.c
drivers/scsi/st.c
drivers/serial/68328serial.c
drivers/serial/8250.c
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/imx.c
drivers/serial/ioc3_serial.c [new file with mode: 0644]
drivers/serial/pmac_zilog.c
drivers/serial/serial_core.c
drivers/sh/superhyway/superhyway.c
drivers/sn/Kconfig
drivers/sn/Makefile
drivers/sn/ioc3.c [new file with mode: 0644]
drivers/spi/Kconfig [new file with mode: 0644]
drivers/spi/Makefile [new file with mode: 0644]
drivers/spi/spi.c [new file with mode: 0644]
drivers/spi/spi_bitbang.c [new file with mode: 0644]
drivers/spi/spi_butterfly.c [new file with mode: 0644]
drivers/usb/atm/usbatm.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/zero.c
drivers/usb/input/Kconfig
drivers/usb/input/hid-core.c
drivers/usb/input/hid-input.c
drivers/usb/input/hid.h
drivers/usb/input/pid.c
drivers/usb/input/wacom.c
drivers/usb/serial/bus.c
drivers/usb/serial/pl2303.c
drivers/video/68328fb.c
drivers/video/acornfb.c
drivers/video/amba-clcd.c
drivers/video/amifb.c
drivers/video/arcfb.c
drivers/video/atafb.c
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_base.c
drivers/video/aty/radeon_pm.c
drivers/video/au1100fb.c
drivers/video/bw2.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/controlfb.c
drivers/video/fbmem.c
drivers/video/ffb.c
drivers/video/gbefb.c
drivers/video/geode/gx1fb_core.c
drivers/video/igafb.c
drivers/video/imsttfb.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/kyro/fbdev.c
drivers/video/leo.c
drivers/video/matrox/matroxfb_base.c
drivers/video/matrox/matroxfb_crtc2.c
drivers/video/matrox/matroxfb_maven.c
drivers/video/neofb.c
drivers/video/p9100.c
drivers/video/pm3fb.c
drivers/video/pmag-aa-fb.c
drivers/video/pxafb.c
drivers/video/radeonfb.c
drivers/video/sa1100fb.c
drivers/video/sgivwfb.c
drivers/video/sis/sis_main.c
drivers/video/sis/sis_main.h
drivers/video/sstfb.c
drivers/video/tcx.c
drivers/video/vfb.c
drivers/zorro/zorro-driver.c
fs/9p/conv.c
fs/autofs4/root.c
fs/binfmt_elf.c
fs/binfmt_misc.c
fs/bio.c
fs/buffer.c
fs/char_dev.c
fs/compat.c
fs/dcache.c
fs/exec.c
fs/ext2/namei.c
fs/ext3/namei.c
fs/fcntl.c
fs/hugetlbfs/inode.c
fs/isofs/namei.c
fs/jffs2/build.c
fs/jffs2/nodelist.c
fs/lockd/xdr.c
fs/mbcache.c
fs/namei.c
fs/ncpfs/inode.c
fs/ncpfs/ioctl.c
fs/nfsd/nfsxdr.c
fs/pipe.c
fs/proc/proc_devtree.c
fs/proc/proc_misc.c
fs/quota_v2.c
fs/reiserfs/namei.c
fs/smbfs/Makefile
fs/smbfs/inode.c
fs/smbfs/request.c
fs/ufs/balloc.c
fs/ufs/ialloc.c
fs/ufs/inode.c
fs/ufs/super.c
fs/ufs/util.h
include/asm-arm/arch-ixp2000/ixp2000-regs.h
include/asm-arm/arch-versatile/entry-macro.S
include/asm-arm/arch-versatile/platform.h
include/asm-arm/hardware/vic.h [new file with mode: 0644]
include/asm-arm/mach/arch.h
include/asm-arm/page.h
include/asm-arm/processor.h
include/asm-arm/ptrace.h
include/asm-arm/stat.h
include/asm-arm/statfs.h
include/asm-arm/unistd.h
include/asm-generic/atomic.h
include/asm-i386/bitops.h
include/asm-i386/current.h
include/asm-i386/string.h
include/asm-i386/uaccess.h
include/asm-ia64/kprobes.h
include/asm-ia64/sn/ioc3.h [new file with mode: 0644]
include/asm-ia64/sn/sn_sal.h
include/asm-ia64/sn/xp.h
include/asm-ia64/sn/xpc.h [new file with mode: 0644]
include/asm-ia64/thread_info.h
include/asm-powerpc/atomic.h
include/asm-powerpc/bitops.h
include/asm-powerpc/cputable.h
include/asm-powerpc/elf.h
include/asm-powerpc/futex.h
include/asm-powerpc/hvcall.h
include/asm-powerpc/kexec.h
include/asm-powerpc/lppaca.h
include/asm-powerpc/paca.h
include/asm-powerpc/ppc_asm.h
include/asm-powerpc/prom.h
include/asm-powerpc/spinlock.h
include/asm-powerpc/synch.h
include/asm-powerpc/system.h
include/asm-powerpc/time.h
include/asm-ppc/prom.h
include/asm-s390/s390_rdev.h
include/asm-s390/sigcontext.h
include/asm-s390/system.h
include/asm-x86_64/fixmap.h
include/asm-x86_64/uaccess.h
include/linux/auxvec.h
include/linux/compiler-gcc3.h
include/linux/compiler-gcc4.h
include/linux/cpuset.h
include/linux/device.h
include/linux/fb.h
include/linux/fs.h
include/linux/hardirq.h
include/linux/ide.h
include/linux/ioc3.h [new file with mode: 0644]
include/linux/kernel.h
include/linux/mempolicy.h
include/linux/mm.h
include/linux/ncp_fs.h
include/linux/netfilter/nf_conntrack_common.h
include/linux/netfilter/x_tables.h [new file with mode: 0644]
include/linux/netfilter/xt_CLASSIFY.h [new file with mode: 0644]
include/linux/netfilter/xt_CONNMARK.h [new file with mode: 0644]
include/linux/netfilter/xt_MARK.h [new file with mode: 0644]
include/linux/netfilter/xt_NFQUEUE.h [new file with mode: 0644]
include/linux/netfilter/xt_comment.h [new file with mode: 0644]
include/linux/netfilter/xt_connbytes.h [new file with mode: 0644]
include/linux/netfilter/xt_connmark.h [new file with mode: 0644]
include/linux/netfilter/xt_conntrack.h [new file with mode: 0644]
include/linux/netfilter/xt_dccp.h [new file with mode: 0644]
include/linux/netfilter/xt_helper.h [new file with mode: 0644]
include/linux/netfilter/xt_length.h [new file with mode: 0644]
include/linux/netfilter/xt_limit.h [new file with mode: 0644]
include/linux/netfilter/xt_mac.h [new file with mode: 0644]
include/linux/netfilter/xt_mark.h [new file with mode: 0644]
include/linux/netfilter/xt_physdev.h [new file with mode: 0644]
include/linux/netfilter/xt_pkttype.h [new file with mode: 0644]
include/linux/netfilter/xt_realm.h [new file with mode: 0644]
include/linux/netfilter/xt_sctp.h [new file with mode: 0644]
include/linux/netfilter/xt_state.h [new file with mode: 0644]
include/linux/netfilter/xt_string.h [new file with mode: 0644]
include/linux/netfilter/xt_tcpmss.h [new file with mode: 0644]
include/linux/netfilter/xt_tcpudp.h [new file with mode: 0644]
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_ipv4/ip_conntrack.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv4/ipt_CLASSIFY.h
include/linux/netfilter_ipv4/ipt_CONNMARK.h
include/linux/netfilter_ipv4/ipt_MARK.h
include/linux/netfilter_ipv4/ipt_NFQUEUE.h
include/linux/netfilter_ipv4/ipt_comment.h
include/linux/netfilter_ipv4/ipt_connbytes.h
include/linux/netfilter_ipv4/ipt_connmark.h
include/linux/netfilter_ipv4/ipt_conntrack.h
include/linux/netfilter_ipv4/ipt_dccp.h
include/linux/netfilter_ipv4/ipt_helper.h
include/linux/netfilter_ipv4/ipt_length.h
include/linux/netfilter_ipv4/ipt_limit.h
include/linux/netfilter_ipv4/ipt_mac.h
include/linux/netfilter_ipv4/ipt_mark.h
include/linux/netfilter_ipv4/ipt_physdev.h
include/linux/netfilter_ipv4/ipt_pkttype.h
include/linux/netfilter_ipv4/ipt_realm.h
include/linux/netfilter_ipv4/ipt_state.h
include/linux/netfilter_ipv4/ipt_string.h
include/linux/netfilter_ipv4/ipt_tcpmss.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netfilter_ipv6/ip6t_MARK.h
include/linux/netfilter_ipv6/ip6t_length.h
include/linux/netfilter_ipv6/ip6t_limit.h
include/linux/netfilter_ipv6/ip6t_mac.h
include/linux/netfilter_ipv6/ip6t_mark.h
include/linux/netfilter_ipv6/ip6t_physdev.h
include/linux/pci_ids.h
include/linux/proc_fs.h
include/linux/raid_class.h
include/linux/sched.h
include/linux/serial_core.h
include/linux/shmem_fs.h
include/linux/smb_fs.h
include/linux/socket.h
include/linux/spi/ads7846.h [new file with mode: 0644]
include/linux/spi/flash.h [new file with mode: 0644]
include/linux/spi/spi.h [new file with mode: 0644]
include/linux/spi/spi_bitbang.h [new file with mode: 0644]
include/linux/swap.h
include/linux/tipc.h [new file with mode: 0644]
include/linux/tipc_config.h [new file with mode: 0644]
include/net/genetlink.h
include/net/netfilter/ipv4/nf_conntrack_ipv4.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_tuple.h
include/net/sctp/sctp.h
include/net/tipc/tipc.h [new file with mode: 0644]
include/net/tipc/tipc_bearer.h [new file with mode: 0644]
include/net/tipc/tipc_msg.h [new file with mode: 0644]
include/net/tipc/tipc_port.h [new file with mode: 0644]
include/rdma/ib_verbs.h
include/scsi/iscsi_if.h
include/scsi/scsi.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_host.h
include/scsi/scsi_transport.h
include/scsi/scsi_transport_fc.h
include/scsi/scsi_transport_iscsi.h
include/scsi/scsi_transport_spi.h
init/main.c
ipc/mqueue.c
kernel/cpuset.c
kernel/exit.c
kernel/posix-timers.c
kernel/sched.c
kernel/signal.c
kernel/sysctl.c
kernel/workqueue.c
lib/Kconfig.debug
mm/mempolicy.c
mm/oom_kill.c
mm/shmem.c
net/Kconfig
net/Makefile
net/bridge/netfilter/ebt_log.c
net/core/filter.c
net/ieee80211/ieee80211_module.c
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_tx.c
net/ieee80211/ieee80211_wx.c
net/ipv4/fib_frontend.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arpt_mangle.c
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_nat_rule.c
net/ipv4/netfilter/ip_nat_standalone.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLASSIFY.c [deleted file]
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_CONNMARK.c [deleted file]
net/ipv4/netfilter/ipt_DSCP.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv4/netfilter/ipt_MARK.c [deleted file]
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_NETMAP.c
net/ipv4/netfilter/ipt_NFQUEUE.c [deleted file]
net/ipv4/netfilter/ipt_NOTRACK.c [deleted file]
net/ipv4/netfilter/ipt_REDIRECT.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_SAME.c
net/ipv4/netfilter/ipt_TCPMSS.c
net/ipv4/netfilter/ipt_TOS.c
net/ipv4/netfilter/ipt_TTL.c
net/ipv4/netfilter/ipt_ULOG.c
net/ipv4/netfilter/ipt_addrtype.c
net/ipv4/netfilter/ipt_ah.c
net/ipv4/netfilter/ipt_comment.c [deleted file]
net/ipv4/netfilter/ipt_connbytes.c [deleted file]
net/ipv4/netfilter/ipt_connmark.c [deleted file]
net/ipv4/netfilter/ipt_conntrack.c [deleted file]
net/ipv4/netfilter/ipt_dccp.c [deleted file]
net/ipv4/netfilter/ipt_dscp.c
net/ipv4/netfilter/ipt_ecn.c
net/ipv4/netfilter/ipt_esp.c
net/ipv4/netfilter/ipt_hashlimit.c
net/ipv4/netfilter/ipt_helper.c [deleted file]
net/ipv4/netfilter/ipt_iprange.c
net/ipv4/netfilter/ipt_length.c [deleted file]
net/ipv4/netfilter/ipt_limit.c [deleted file]
net/ipv4/netfilter/ipt_mac.c [deleted file]
net/ipv4/netfilter/ipt_mark.c [deleted file]
net/ipv4/netfilter/ipt_multiport.c
net/ipv4/netfilter/ipt_owner.c
net/ipv4/netfilter/ipt_physdev.c [deleted file]
net/ipv4/netfilter/ipt_pkttype.c [deleted file]
net/ipv4/netfilter/ipt_realm.c [deleted file]
net/ipv4/netfilter/ipt_recent.c
net/ipv4/netfilter/ipt_sctp.c [deleted file]
net/ipv4/netfilter/ipt_state.c [deleted file]
net/ipv4/netfilter/ipt_string.c [deleted file]
net/ipv4/netfilter/ipt_tcpmss.c [deleted file]
net/ipv4/netfilter/ipt_tos.c
net/ipv4/netfilter/ipt_ttl.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/xfrm4_state.c
net/ipv6/addrconf.c
net/ipv6/ah6.c
net/ipv6/anycast.c
net/ipv6/esp6.c
net/ipv6/icmp.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ipcomp6.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_HL.c
net/ipv6/netfilter/ip6t_LOG.c
net/ipv6/netfilter/ip6t_MARK.c [deleted file]
net/ipv6/netfilter/ip6t_NFQUEUE.c [deleted file]
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/ip6t_ah.c
net/ipv6/netfilter/ip6t_dst.c
net/ipv6/netfilter/ip6t_esp.c
net/ipv6/netfilter/ip6t_eui64.c
net/ipv6/netfilter/ip6t_frag.c
net/ipv6/netfilter/ip6t_hbh.c
net/ipv6/netfilter/ip6t_hl.c
net/ipv6/netfilter/ip6t_ipv6header.c
net/ipv6/netfilter/ip6t_length.c [deleted file]
net/ipv6/netfilter/ip6t_limit.c [deleted file]
net/ipv6/netfilter/ip6t_mac.c [deleted file]
net/ipv6/netfilter/ip6t_mark.c [deleted file]
net/ipv6/netfilter/ip6t_multiport.c
net/ipv6/netfilter/ip6t_owner.c
net/ipv6/netfilter/ip6t_physdev.c [deleted file]
net/ipv6/netfilter/ip6t_rt.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/xfrm6_state.c
net/ipv6/xfrm6_tunnel.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nfnetlink.c
net/netfilter/x_tables.c [new file with mode: 0644]
net/netfilter/xt_CLASSIFY.c [new file with mode: 0644]
net/netfilter/xt_CONNMARK.c [new file with mode: 0644]
net/netfilter/xt_MARK.c [new file with mode: 0644]
net/netfilter/xt_NFQUEUE.c [new file with mode: 0644]
net/netfilter/xt_NOTRACK.c [new file with mode: 0644]
net/netfilter/xt_comment.c [new file with mode: 0644]
net/netfilter/xt_connbytes.c [new file with mode: 0644]
net/netfilter/xt_connmark.c [new file with mode: 0644]
net/netfilter/xt_conntrack.c [new file with mode: 0644]
net/netfilter/xt_dccp.c [new file with mode: 0644]
net/netfilter/xt_helper.c [new file with mode: 0644]
net/netfilter/xt_length.c [new file with mode: 0644]
net/netfilter/xt_limit.c [new file with mode: 0644]
net/netfilter/xt_mac.c [new file with mode: 0644]
net/netfilter/xt_mark.c [new file with mode: 0644]
net/netfilter/xt_physdev.c [new file with mode: 0644]
net/netfilter/xt_pkttype.c [new file with mode: 0644]
net/netfilter/xt_realm.c [new file with mode: 0644]
net/netfilter/xt_sctp.c [new file with mode: 0644]
net/netfilter/xt_state.c [new file with mode: 0644]
net/netfilter/xt_string.c [new file with mode: 0644]
net/netfilter/xt_tcpmss.c [new file with mode: 0644]
net/netfilter/xt_tcpudp.c [new file with mode: 0644]
net/netlink/genetlink.c
net/sched/Kconfig
net/sched/act_ipt.c
net/sctp/ipv6.c
net/sctp/sm_statefuns.c
net/tipc/Kconfig [new file with mode: 0644]
net/tipc/Makefile [new file with mode: 0644]
net/tipc/addr.c [new file with mode: 0644]
net/tipc/addr.h [new file with mode: 0644]
net/tipc/bcast.c [new file with mode: 0644]
net/tipc/bcast.h [new file with mode: 0644]
net/tipc/bearer.c [new file with mode: 0644]
net/tipc/bearer.h [new file with mode: 0644]
net/tipc/cluster.c [new file with mode: 0644]
net/tipc/cluster.h [new file with mode: 0644]
net/tipc/config.c [new file with mode: 0644]
net/tipc/config.h [new file with mode: 0644]
net/tipc/core.c [new file with mode: 0644]
net/tipc/core.h [new file with mode: 0644]
net/tipc/dbg.c [new file with mode: 0644]
net/tipc/dbg.h [new file with mode: 0644]
net/tipc/discover.c [new file with mode: 0644]
net/tipc/discover.h [new file with mode: 0644]
net/tipc/eth_media.c [new file with mode: 0644]
net/tipc/handler.c [new file with mode: 0644]
net/tipc/link.c [new file with mode: 0644]
net/tipc/link.h [new file with mode: 0644]
net/tipc/msg.c [new file with mode: 0644]
net/tipc/msg.h [new file with mode: 0644]
net/tipc/name_distr.c [new file with mode: 0644]
net/tipc/name_distr.h [new file with mode: 0644]
net/tipc/name_table.c [new file with mode: 0644]
net/tipc/name_table.h [new file with mode: 0644]
net/tipc/net.c [new file with mode: 0644]
net/tipc/net.h [new file with mode: 0644]
net/tipc/netlink.c [new file with mode: 0644]
net/tipc/node.c [new file with mode: 0644]
net/tipc/node.h [new file with mode: 0644]
net/tipc/node_subscr.c [new file with mode: 0644]
net/tipc/node_subscr.h [new file with mode: 0644]
net/tipc/port.c [new file with mode: 0644]
net/tipc/port.h [new file with mode: 0644]
net/tipc/ref.c [new file with mode: 0644]
net/tipc/ref.h [new file with mode: 0644]
net/tipc/socket.c [new file with mode: 0644]
net/tipc/subscr.c [new file with mode: 0644]
net/tipc/subscr.h [new file with mode: 0644]
net/tipc/user_reg.c [new file with mode: 0644]
net/tipc/user_reg.h [new file with mode: 0644]
net/tipc/zone.c [new file with mode: 0644]
net/tipc/zone.h [new file with mode: 0644]
security/selinux/avc.c
security/selinux/hooks.c
sound/oss/esssolo1.c
sound/pci/es1968.c

index dd311cff1cc30b78ebb1dbe8593fb47866e0a78b..6bd30fdd0786b9a7c64aa4c34f5a732b4c7096e0 100644 (file)
@@ -143,7 +143,7 @@ KernelNewbies:
        http://kernelnewbies.org/
 
 Linux USB project:
-       http://linux-usb.sourceforge.net/
+       http://www.linux-usb.org/
 
 How to NOT write kernel driver by arjanv@redhat.com
        http://people.redhat.com/arjanv/olspaper.pdf
index 6198e5ebcf65be906f801acd1f5df836c3d4d93c..c2c85bcb3d438b983ccc1535acbbd185867e26c3 100644 (file)
@@ -478,10 +478,11 @@ Andrew Morton, "The perfect patch" (tpp).
 Jeff Garzik, "Linux kernel patch submission format."
   <http://linux.yyz.us/patch-format.html>
 
-Greg Kroah, "How to piss off a kernel subsystem maintainer".
+Greg Kroah-Hartman "How to piss off a kernel subsystem maintainer".
   <http://www.kroah.com/log/2005/03/31/>
   <http://www.kroah.com/log/2005/07/08/>
   <http://www.kroah.com/log/2005/10/19/>
+  <http://www.kroah.com/log/2006/01/11/>
 
 NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!.
   <http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
index 9474501dd6cc4db9b9b0833d5ef5455ff1e4b1e2..b4a1ea76269857137a659e69102b1223b715f6cf 100644 (file)
@@ -123,6 +123,15 @@ Who:       Christoph Hellwig <hch@lst.de>
 
 ---------------------------
 
+What:  CONFIG_FORCED_INLINING
+When:  June 2006
+Why:   Config option is there to see if gcc is good enough. (in january
+        2006). If it is, the behavior should just be the default. If it's not,
+       the option should just go away entirely.
+Who:    Arjan van de Ven
+
+---------------------------
+
 What:  START_ARRAY ioctl for md
 When:  July 2006
 Files: drivers/md/md.c
index 0d783c504eade32e666e7a19b6fa89f85bfb9416..dbe4d87d26154dfe422bd20b51551509c0a99ef5 100644 (file)
@@ -78,6 +78,18 @@ use up all the memory on the machine; but enhances the scalability of
 that instance in a system with many cpus making intensive use of it.
 
 
+tmpfs has a mount option to set the NUMA memory allocation policy for
+all files in that instance:
+mpol=interleave                prefers to allocate memory from each node in turn
+mpol=default           prefers to allocate memory from the local node
+mpol=bind              prefers to allocate from mpol_nodelist
+mpol=preferred         prefers to allocate from first node in mpol_nodelist
+
+The following mount option is used in conjunction with mpol=interleave,
+mpol=bind or mpol=preferred:
+mpol_nodelist: nodelist suitable for parsing with nodelist_parse.
+
+
 To specify the initial root directory you can use the following mount
 options:
 
index fe11fccf7e41bd7bb1abd38be8c73cb52775cc2d..1cbcf65b764b47137b0db013654e55f224c3c32c 100644 (file)
@@ -471,7 +471,7 @@ running once the system is up.
                        arch/i386/kernel/cpu/cpufreq/elanfreq.c.
 
        elevator=       [IOSCHED]
-                       Format: {"as" | "cfq" | "deadline" | "noop"}
+                       Format: {"anticipatory" | "cfq" | "deadline" | "noop"}
                        See Documentation/block/as-iosched.txt and
                        Documentation/block/deadline-iosched.txt for details.
 
@@ -712,9 +712,17 @@ running once the system is up.
        load_ramdisk=   [RAM] List of ramdisks to load from floppy
                        See Documentation/ramdisk.txt.
 
-       lockd.udpport=  [NFS]
+       lockd.nlm_grace_period=P  [NFS] Assign grace period.
+                       Format: <integer>
+
+       lockd.nlm_tcpport=N     [NFS] Assign TCP port.
+                       Format: <integer>
 
-       lockd.tcpport=  [NFS]
+       lockd.nlm_timeout=T     [NFS] Assign timeout value.
+                       Format: <integer>
+
+       lockd.nlm_udpport=M     [NFS] Assign UDP port.
+                       Format: <integer>
 
        logibm.irq=     [HW,MOUSE] Logitech Bus Mouse Driver
                        Format: <irq>
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
new file mode 100644 (file)
index 0000000..820fd07
--- /dev/null
@@ -0,0 +1,108 @@
+AACRAID Driver for Linux (take two)
+
+Introduction
+-------------------------
+The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+RAID controllers. This is a major rewrite from the original
+Adaptec supplied driver. It has signficantly cleaned up both the code
+and the running binary size (the module is less than half the size of
+the original).
+
+Supported Cards/Chipsets
+-------------------------
+       PCI ID (pci.ids)        OEM     Product
+       9005:0285:9005:028a     Adaptec 2020ZCR (Skyhawk)
+       9005:0285:9005:028e     Adaptec 2020SA (Skyhawk)
+       9005:0285:9005:028b     Adaptec 2025ZCR (Terminator)
+       9005:0285:9005:028f     Adaptec 2025SA (Terminator)
+       9005:0285:9005:0286     Adaptec 2120S (Crusader)
+       9005:0286:9005:028d     Adaptec 2130S (Lancer)
+       9005:0285:9005:0285     Adaptec 2200S (Vulcan)
+       9005:0285:9005:0287     Adaptec 2200S (Vulcan-2m)
+       9005:0286:9005:028c     Adaptec 2230S (Lancer)
+       9005:0286:9005:028c     Adaptec 2230SLP (Lancer)
+       9005:0285:9005:0296     Adaptec 2240S (SabreExpress)
+       9005:0285:9005:0290     Adaptec 2410SA (Jaguar)
+       9005:0285:9005:0293     Adaptec 21610SA (Corsair-16)
+       9005:0285:103c:3227     Adaptec 2610SA (Bearcat)
+       9005:0285:9005:0292     Adaptec 2810SA (Corsair-8)
+       9005:0285:9005:0294     Adaptec Prowler
+       9005:0286:9005:029d     Adaptec 2420SA (Intruder)
+       9005:0286:9005:029c     Adaptec 2620SA (Intruder)
+       9005:0286:9005:029b     Adaptec 2820SA (Intruder)
+       9005:0286:9005:02a7     Adaptec 2830SA (Skyray)
+       9005:0286:9005:02a8     Adaptec 2430SA (Skyray)
+       9005:0285:9005:0288     Adaptec 3230S (Harrier)
+       9005:0285:9005:0289     Adaptec 3240S (Tornado)
+       9005:0285:9005:0298     Adaptec 4000SAS (BlackBird)
+       9005:0285:9005:0297     Adaptec 4005SAS (AvonPark)
+       9005:0285:9005:0299     Adaptec 4800SAS (Marauder-X)
+       9005:0285:9005:029a     Adaptec 4805SAS (Marauder-E)
+       9005:0286:9005:02a2     Adaptec 4810SAS (Hurricane)
+       1011:0046:9005:0364     Adaptec 5400S (Mustang)
+       1011:0046:9005:0365     Adaptec 5400S (Mustang)
+       9005:0283:9005:0283     Adaptec Catapult (3210S with arc firmware)
+       9005:0284:9005:0284     Adaptec Tomcat (3410S with arc firmware)
+       9005:0287:9005:0800     Adaptec Themisto (Jupiter)
+       9005:0200:9005:0200     Adaptec Themisto (Jupiter)
+       9005:0286:9005:0800     Adaptec Callisto (Jupiter)
+       1011:0046:9005:1364     Dell    PERC 2/QC (Quad Channel, Mustang)
+       1028:0001:1028:0001     Dell    PERC 2/Si (Iguana)
+       1028:0003:1028:0003     Dell    PERC 3/Si (SlimFast)
+       1028:0002:1028:0002     Dell    PERC 3/Di (Opal)
+       1028:0004:1028:0004     Dell    PERC 3/DiF (Iguana)
+       1028:0002:1028:00d1     Dell    PERC 3/DiV (Viper)
+       1028:0002:1028:00d9     Dell    PERC 3/DiL (Lexus)
+       1028:000a:1028:0106     Dell    PERC 3/DiJ (Jaguar)
+       1028:000a:1028:011b     Dell    PERC 3/DiD (Dagger)
+       1028:000a:1028:0121     Dell    PERC 3/DiB (Boxster)
+       9005:0285:1028:0287     Dell    PERC 320/DC (Vulcan)
+       9005:0285:1028:0291     Dell    CERC 2 (DellCorsair)
+       1011:0046:103c:10c2     HP      NetRAID-4M (Mustang)
+       9005:0285:17aa:0286     Legend  S220 (Crusader)
+       9005:0285:17aa:0287     Legend  S230 (Vulcan)
+       9005:0285:9005:0290     IBM     ServeRAID 7t (Jaguar)
+       9005:0285:1014:02F2     IBM     ServeRAID 8i (AvonPark)
+       9005:0285:1014:0312     IBM     ServeRAID 8i (AvonParkLite)
+       9005:0286:1014:9580     IBM     ServeRAID 8k/8k-l8 (Aurora)
+       9005:0286:1014:9540     IBM     ServeRAID 8k/8k-l4 (AuroraLite)
+       9005:0286:9005:029f     ICP     ICP9014R0 (Lancer)
+       9005:0286:9005:029e     ICP     ICP9024R0 (Lancer)
+       9005:0286:9005:02a0     ICP     ICP9047MA (Lancer)
+       9005:0286:9005:02a1     ICP     ICP9087MA (Lancer)
+       9005:0286:9005:02a4     ICP     ICP9085LI (Marauder-X)
+       9005:0286:9005:02a5     ICP     ICP5085BR (Marauder-E)
+       9005:0286:9005:02a3     ICP     ICP5085AU (Hurricane)
+       9005:0286:9005:02a6     ICP     ICP9067MA (Intruder-6)
+       9005:0286:9005:02a9     ICP     ICP5087AU (Skyray)
+       9005:0286:9005:02aa     ICP     ICP5047AU (Skyray)
+
+People
+-------------------------
+Alan Cox <alan@redhat.com>
+Christoph Hellwig <hch@infradead.org>  (updates for new-style PCI probing and SCSI host registration,
+                                        small cleanups/fixes)
+Matt Domsch <matt_domsch@dell.com>     (revision ioctl, adapter messages)
+Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
+                                        added new ioctls, changed scsi interface to use new error handler,
+                                        increased the number of fibs and outstanding commands to a container)
+
+                                       (fixed 64bit and 64G memory model, changed confusing naming convention
+                                        where fibs that go to the hardware are consistently called hw_fibs and
+                                        not just fibs like the name of the driver tracking structure)
+Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas. Performance tuning, card failover and bug mitigations.
+
+Original Driver
+-------------------------
+Adaptec Unix OEM Product Group
+
+Mailing List
+-------------------------
+linux-scsi@vger.kernel.org (Interested parties troll here)
+Also note this is very different to Brian's original driver
+so don't expect him to support it.
+Adaptec does support this driver.  Contact Adaptec tech support or
+aacraid@adaptec.com
+
+Original by Brian Boerner February 2001
+Rewritten by Alan Cox, November 2001
diff --git a/Documentation/spi/butterfly b/Documentation/spi/butterfly
new file mode 100644 (file)
index 0000000..a2e8c8d
--- /dev/null
@@ -0,0 +1,57 @@
+spi_butterfly - parport-to-butterfly adapter driver
+===================================================
+
+This is a hardware and software project that includes building and using
+a parallel port adapter cable, together with an "AVR Butterfly" to run
+firmware for user interfacing and/or sensors.  A Butterfly is a $US20
+battery powered card with an AVR microcontroller and lots of goodies:
+sensors, LCD, flash, toggle stick, and more.  You can use AVR-GCC to
+develop firmware for this, and flash it using this adapter cable.
+
+You can make this adapter from an old printer cable and solder things
+directly to the Butterfly.  Or (if you have the parts and skills) you
+can come up with something fancier, providing ciruit protection to the
+Butterfly and the printer port, or with a better power supply than two
+signal pins from the printer port.
+
+
+The first cable connections will hook Linux up to one SPI bus, with the
+AVR and a DataFlash chip; and to the AVR reset line.  This is all you
+need to reflash the firmware, and the pins are the standard Atmel "ISP"
+connector pins (used also on non-Butterfly AVR boards).
+
+       Signal    Butterfly       Parport (DB-25)
+       ------    ---------       ---------------
+       SCK     = J403.PB1/SCK  = pin 2/D0
+       RESET   = J403.nRST     = pin 3/D1
+       VCC     = J403.VCC_EXT  = pin 8/D6
+       MOSI    = J403.PB2/MOSI = pin 9/D7
+       MISO    = J403.PB3/MISO = pin 11/S7,nBUSY
+       GND     = J403.GND      = pin 23/GND
+
+Then to let Linux master that bus to talk to the DataFlash chip, you must
+(a) flash new firmware that disables SPI (set PRR.2, and disable pullups
+by clearing PORTB.[0-3]); (b) configure the mtd_dataflash driver; and
+(c) cable in the chipselect.
+
+       Signal    Butterfly       Parport (DB-25)
+       ------    ---------       ---------------
+       VCC     = J400.VCC_EXT  = pin 7/D5
+       SELECT  = J400.PB0/nSS  = pin 17/C3,nSELECT
+       GND     = J400.GND      = pin 24/GND
+
+The "USI" controller, using J405, can be used for a second SPI bus.  That
+would let you talk to the AVR over SPI, running firmware that makes it act
+as an SPI slave, while letting either Linux or the AVR use the DataFlash.
+There are plenty of spare parport pins to wire this one up, such as:
+
+       Signal    Butterfly       Parport (DB-25)
+       ------    ---------       ---------------
+       SCK     = J403.PE4/USCK = pin 5/D3
+       MOSI    = J403.PE5/DI   = pin 6/D4
+       MISO    = J403.PE6/DO   = pin 12/S5,nPAPEROUT
+       GND     = J403.GND      = pin 22/GND
+
+       IRQ     = J402.PF4      = pin 10/S6,ACK
+       GND     = J402.GND(P2)  = pin 25/GND
+
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
new file mode 100644 (file)
index 0000000..a5ffba3
--- /dev/null
@@ -0,0 +1,457 @@
+Overview of Linux kernel SPI support
+====================================
+
+02-Dec-2005
+
+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),
+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
+commonly used.  Each clock cycle shifts data out and data in; the clock
+doesn't cycle except when there is data to shift.
+
+SPI masters may use a "chip select" line to activate a given SPI slave
+device, so those three signal wires may be connected to several chips
+in parallel.  All SPI slaves support chipselects.  Some devices have
+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).
+
+  - SPI may be used for request/response style device protocols, as with
+    touchscreen sensors and memory chips.
+
+  - It may also be used to stream data in either direction (half duplex),
+    or both of them at the same time (full duplex).
+
+  - Some devices may use eight bit words.  Others may different word
+    lengths, such as streams of 12-bit or 20-bit digital samples.
+
+In the same way, SPI slaves will only rarely support any kind of automatic
+discovery/enumeration protocol.  The tree of slave devices accessible from
+a given SPI master will normally be set up manually, with configuration
+tables.
+
+SPI is only one of the names used by such four-wire protocols, and
+most controllers have no problem handling "MicroWire" (think of it as
+half-duplex SPI, for request/response protocols), SSP ("Synchronous
+Serial Protocol"), PSP ("Programmable Serial Protocol"), and other
+related protocols.
+
+Microcontrollers often support both master and slave sides of the SPI
+protocol.  This document (and Linux) currently only supports the master
+side of SPI interactions.
+
+
+Who uses it?  On what kinds of systems?
+---------------------------------------
+Linux developers using SPI are probably writing device drivers for embedded
+systems boards.  SPI is used to control external chips, and it is also a
+protocol supported by every MMC or SD memory card.  (The older "DataFlash"
+cards, predating MMC cards but using the same connectors and card shape,
+support only SPI.)  Some PC hardware uses SPI flash for BIOS code.
+
+SPI slave chips range from digital/analog converters used for analog
+sensors and codecs, to memory, to peripherals like USB controllers
+or Ethernet adapters; and more.
+
+Most systems using SPI will integrate a few devices on a mainboard.
+Some provide SPI links on expansion connectors; in cases where no
+dedicated SPI controller exists, GPIO pins can be used to create a
+low speed "bitbanging" adapter.  Very few systems will "hotplug" an SPI
+controller; the reasons to use SPI focus on low cost and simple operation,
+and if dynamic reconfiguration is important, USB will often be a more
+appropriate low-pincount peripheral bus.
+
+Many microcontrollers that can run Linux integrate one or more I/O
+interfaces with SPI modes.  Given SPI support, they could use MMC or SD
+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.
+
+SPI requests always go into I/O queues.  Requests for a given SPI device
+are always executed in FIFO order, and complete asynchronously through
+completion callbacks.  There are also some simple synchronous wrappers
+for those calls, including ones for common transaction types like writing
+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
+       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.
+
+  Protocol drivers ... these pass messages through the controller
+       driver to communicate with a Slave or Master device on the
+       other side of an SPI link.
+
+So for example one protocol driver might talk to the MTD layer to export
+data to filesystems stored on SPI flash like DataFlash; and others might
+control audio interfaces, present touchscreen sensors as input interfaces,
+or monitor temperature and voltage levels during industrial processing.
+And those might all be sharing the same controller driver.
+
+A "struct spi_device" encapsulates the master-side interface between
+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
+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",
+       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
+
+   /sys/bus/spi/drivers/D ... driver for one or more spi*.* devices
+
+   /sys/class/spi_master/spiB ... class device for the controller
+       managing bus "B".  All the spiB.* devices share the same
+       physical SPI bus segment, with SCLK, MOSI, and MISO.
+
+
+How does board-specific init code declare SPI devices?
+------------------------------------------------------
+Linux needs several kinds of information to properly configure SPI devices.
+That information is normally provided by board-specific code, even for
+chips that do support some of automated discovery/enumeration.
+
+DECLARE CONTROLLERS
+
+The first kind of information is a list of what SPI controllers exist.
+For System-on-Chip (SOC) based boards, these will usually be platform
+devices, and the controller may need some platform_data in order to
+operate properly.  The "struct platform_device" will include resources
+like the physical address of the controller's first register and its IRQ.
+
+Platforms will often abstract the "register SPI controller" operation,
+maybe coupling it with code to initialize pin configurations, so that
+the arch/.../mach-*/board-*.c files for several boards can all share the
+same basic controller setup code.  This is because most SOCs have several
+SPI-capable controllers, and only the ones actually usable on a given
+board should normally be set up and registered.
+
+So for example arch/.../mach-*/board-*.c files might have code like:
+
+       #include <asm/arch/spi.h>       /* for mysoc_spi_data */
+
+       /* if your mach-* infrastructure doesn't support kernels that can
+        * run on multiple boards, pdata wouldn't benefit from "__init".
+        */
+       static struct mysoc_spi_data __init pdata = { ... };
+
+       static __init board_init(void)
+       {
+               ...
+               /* this board only uses SPI controller #2 */
+               mysoc_register_spi(2, &pdata);
+               ...
+       }
+
+And SOC-specific utility code might look something like:
+
+       #include <asm/arch/spi.h>
+
+       static struct platform_device spi2 = { ... };
+
+       void mysoc_register_spi(unsigned n, struct mysoc_spi_data *pdata)
+       {
+               struct mysoc_spi_data *pdata2;
+
+               pdata2 = kmalloc(sizeof *pdata2, GFP_KERNEL);
+               *pdata2 = pdata;
+               ...
+               if (n == 2) {
+                       spi2->dev.platform_data = pdata2;
+                       register_platform_device(&spi2);
+
+                       /* also: set up pin modes so the spi2 signals are
+                        * visible on the relevant pins ... bootloaders on
+                        * production boards may already have done this, but
+                        * developer boards will often need Linux to do it.
+                        */
+               }
+               ...
+       }
+
+Notice how the platform_data for boards may be different, even if the
+same SOC controller is used.  For example, on one board SPI might use
+an external clock, where another derives the SPI clock from current
+settings of some master clock.
+
+
+DECLARE SLAVE DEVICES
+
+The second kind of information is a list of what SPI slave devices exist
+on the target board, often with some board-specific data needed for the
+driver to work correctly.
+
+Normally your arch/.../mach-*/board-*.c files would provide a small table
+listing the SPI devices on each board.  (This would typically be only a
+small handful.)  That might look like:
+
+       static struct ads7846_platform_data ads_info = {
+               .vref_delay_usecs       = 100,
+               .x_plate_ohms           = 580,
+               .y_plate_ohms           = 410,
+       };
+
+       static struct spi_board_info spi_board_info[] __initdata = {
+       {
+               .modalias       = "ads7846",
+               .platform_data  = &ads_info,
+               .mode           = SPI_MODE_0,
+               .irq            = GPIO_IRQ(31),
+               .max_speed_hz   = 120000 /* max sample rate at 3V */ * 16,
+               .bus_num        = 1,
+               .chip_select    = 0,
+       },
+       };
+
+Again, notice how board-specific information is provided; each chip may need
+several types.  This example shows generic constraints like the fastest SPI
+clock to allow (a function of board voltage in this case) or how an IRQ pin
+is wired, plus chip-specific constraints like an important delay that's
+changed by the capacitance at one pin.
+
+(There's also "controller_data", information that may be useful to the
+controller driver.  An example would be peripheral-specific DMA tuning
+data or chipselect callbacks.  This is stored in spi_device later.)
+
+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.
+
+Then your board initialization code would register that table with the SPI
+infrastructure, so that it's available later when the SPI master controller
+driver is registered:
+
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+Like with other static board-specific setup, you won't unregister those.
+
+The widely used "card" style computers bundle memory, cpu, and little else
+onto a card that's maybe just thirty square centimeters.  On such systems,
+your arch/.../mach-.../board-*.c file would primarily provide information
+about the devices on the mainboard into which such a card is plugged.  That
+certainly includes SPI devices hooked up through the card connectors!
+
+
+NON-STATIC CONFIGURATIONS
+
+Developer boards often play by different rules than product boards, and one
+example is the potential need to hotplug SPI devices and/or controllers.
+
+For those cases you might need to use use spi_busnum_to_master() to look
+up the spi bus master, and will likely need spi_new_device() to provide the
+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.
+
+
+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.
+
+SPI protocol drivers somewhat resemble platform device drivers:
+
+       static struct spi_driver CHIP_driver = {
+               .driver = {
+                       .name           = "CHIP",
+                       .bus            = &spi_bus_type,
+                       .owner          = THIS_MODULE,
+               },
+
+               .probe          = CHIP_probe,
+               .remove         = __devexit_p(CHIP_remove),
+               .suspend        = CHIP_suspend,
+               .resume         = CHIP_resume,
+       };
+
+The driver core will autmatically attempt to bind this driver to any SPI
+device whose board_info gave a modalias of "CHIP".  Your probe() code
+might look like this unless you're creating a class_device:
+
+       static int __devinit CHIP_probe(struct spi_device *spi)
+       {
+               struct CHIP                     *chip;
+               struct CHIP_platform_data       *pdata;
+
+               /* assuming the driver requires board-specific data: */
+               pdata = &spi->dev.platform_data;
+               if (!pdata)
+                       return -ENODEV;
+
+               /* get memory for driver's per-chip state */
+               chip = kzalloc(sizeof *chip, GFP_KERNEL);
+               if (!chip)
+                       return -ENOMEM;
+               dev_set_drvdata(&spi->dev, chip);
+
+               ... etc
+               return 0;
+       }
+
+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.
+
+  - An spi_message is a sequence of of protocol operations, executed
+    as one atomic sequence.  SPI driver controls include:
+
+      + when bidirectional reads and writes start ... by how its
+        sequence of spi_transfer requests is arranged;
+
+      + optionally defining short delays after transfers ... using
+        the spi_transfer.delay_usecs setting;
+
+      + whether the chipselect becomes inactive after a transfer and
+        any delay ... by using the spi_transfer.cs_change flag;
+
+      + hinting whether the next message is likely to go to this same
+        device ... using the spi_transfer.cs_change flag on the last
+       transfer in that atomic group, and potentially saving costs
+       for chip deselect and select operations.
+
+  - Follow standard kernel rules, and provide DMA-safe buffers in
+    your messages.  That way controller drivers using DMA aren't forced
+    to make extra copies unless the hardware requires it (e.g. working
+    around hardware errata that force the use of bounce buffering).
+
+    If standard dma_map_single() handling of these buffers is inappropriate,
+    you can use spi_message.is_dma_mapped to tell the controller driver
+    that you've already provided the relevant DMA addresses.
+
+  - The basic I/O primitive is spi_async().  Async requests may be
+    issued in any context (irq handler, task, etc) and completion
+    is reported using a callback provided with the message.
+    After any detected error, the chip is deselected and processing
+    of that spi_message is aborted.
+
+  - There are also synchronous wrappers like spi_sync(), and wrappers
+    like spi_read(), spi_write(), and spi_write_then_read().  These
+    may be issued only in contexts that may sleep, and they're all
+    clean (and small, and "optional") layers over spi_async().
+
+  - The spi_write_then_read() call, and convenience wrappers around
+    it, should only be used with small amounts of data where the
+    cost of an extra copy may be ignored.  It's designed to support
+    common RPC-style requests, such as writing an eight bit command
+    and reading a sixteen bit response -- spi_w8r16() being one its
+    wrappers, doing exactly that.
+
+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.
+
+While "spi_device" would be the bottom boundary of the driver, the
+upper boundaries might include sysfs (especially for sensor readings),
+the input layer, ALSA, networking, MTD, the character device framework,
+or other Linux subsystems.
+
+Note that there are two types of memory your driver must manage as part
+of interacting with SPI devices.
+
+  - I/O buffers use the usual Linux rules, and must be DMA-safe.
+    You'd normally allocate them from the heap or free page pool.
+    Don't use the stack, or anything that's declared "static".
+
+  - The spi_message and spi_transfer metadata used to glue those
+    I/O buffers into a group of protocol transactions.  These can
+    be allocated anywhere it's convenient, including as part of
+    other allocate-once driver data structures.  Zero-init these.
+
+If you like, spi_message_alloc() and spi_message_free() convenience
+routines are available to allocate and zero-initialize an spi_message
+with several transfers.
+
+
+How do I write an "SPI Master Controller Driver"?
+-------------------------------------------------
+An SPI controller will probably be registered on the platform_bus; write
+a driver to bind to the device, whichever bus is involved.
+
+The main task of this type of driver is to provide an "spi_master".
+Use spi_alloc_master() to allocate the master, and class_get_devdata()
+to get the driver-private data allocated for that device.
+
+       struct spi_master       *master;
+       struct CONTROLLER       *c;
+
+       master = spi_alloc_master(dev, sizeof *c);
+       if (!master)
+               return -ENODEV;
+
+       c = class_get_devdata(&master->cdev);
+
+The driver will initialize the fields of that spi_master, including the
+bus number (maybe the same as the platform device ID) and three methods
+used to interact with the SPI core and SPI protocol drivers.  It will
+also initialize its own internal state.
+
+    master->setup(struct spi_device *spi)
+       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.
+
+    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.
+
+    master->cleanup(struct spi_device *spi)
+       Your controller driver may use spi_device.controller_state to hold
+       state it dynamically associates with that device.  If you do that,
+       be sure to provide the cleanup() method to free that state.
+
+The bulk of the driver will be managing the I/O queue fed by transfer().
+
+That queue could be purely conceptual.  For example, a driver used only
+for low-frequency sensor acess might be fine using synchronous PIO.
+
+But the queue will probably be very real, using message->queue, PIO,
+often DMA (especially if the root filesystem is in SPI flash), and
+execution contexts like IRQ handlers, tasklets, or workqueues (such
+as keventd).  Your driver can be as fancy, or as simple, as you need.
+
+
+THANKS TO
+---------
+Contributors to Linux-SPI discussions include (in alphabetical order,
+by last name):
+
+David Brownell
+Russell King
+Dmitry Pervushin
+Stephen Street
+Mark Underwood
+Andrew Victor
+Vitaly Wool
+
index 0db72a36e2453e1f47007a6db14ad37ae3004829..ce3c8f52c9196295e5851930778f2713d81d9d47 100644 (file)
@@ -1300,6 +1300,12 @@ M:       ttb@tentacle.dhs.org and rml@novell.com
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
+P:      Sylvain Meyer
+M:      sylvain.meyer@worldonline.fr
+L:      linux-fbdev-devel@lists.sourceforge.net
+S:      Maintained
+
 INTEL 810/815 FRAMEBUFFER DRIVER
 P:      Antonino Daplas
 M:      adaplas@pol.net
@@ -1889,11 +1895,11 @@ W:      http://linux-ntfs.sf.net/
 T:     git kernel.org:/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git
 S:     Maintained
 
-NVIDIA (RIVA) FRAMEBUFFER DRIVER
-P:     Ani Joshi
-M:     ajoshi@shell.unixbox.com
-L:     linux-nvidia@lists.surfsouth.com
-S:     Maintained
+NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER
+P:      Antonino Daplas
+M:      adaplas@pol.net
+L:      linux-fbdev-devel@lists.sourceforge.net
+S:      Maintained
 
 ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
 P:     Mark Fasheh
@@ -2188,6 +2194,12 @@ L:       rtl@rtlinux.org
 W:     www.rtlinux.org
 S:     Maintained
 
+S3 SAVAGE FRAMEBUFFER DRIVER
+P:      Antonino Daplas
+M:      adaplas@pol.net
+L:      linux-fbdev-devel@lists.sourceforge.net
+S:      Maintained
+
 S390
 P:     Martin Schwidefsky
 M:     schwidefsky@de.ibm.com
@@ -2519,6 +2531,19 @@ P:     Romain Lievin
 M:     roms@lpg.ticalc.org
 S:     Maintained
 
+TIPC NETWORK LAYER
+P:     Per Liden
+M:     per.liden@nospam.ericsson.com
+P:     Jon Maloy
+M:     jon.maloy@nospam.ericsson.com
+P:     Allan Stephens
+M:     allan.stephens@nospam.windriver.com
+L:     tipc-discussion@lists.sourceforge.net
+W:     http://tipc.sourceforge.net/
+W:     http://tipc.cslab.ericsson.net/
+T:     git tipc.cslab.ericsson.net:/pub/git/tipc.git
+S:     Maintained
+
 TLAN NETWORK DRIVER
 P:     Samuel Chessman
 M:     chessman@tux.org
@@ -2940,6 +2965,12 @@ M:       dm@sangoma.com
 W:     http://www.sangoma.com
 S:     Supported
 
+WATCHDOG DEVICE DRIVERS
+P:     Wim Van Sebroeck
+M:     wim@iguana.be
+T:     git kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog.git
+S:     Maintained
+
 WAVELAN NETWORK DRIVER & WIRELESS EXTENSIONS
 P:     Jean Tourrilhes
 M:     jt@hpl.hp.com
index deedaf79cdca2325936f63b511b3744163587bd6..673148e07603778eae148651d432cb6351cac96f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@ export srctree objtree VPATH TOPDIR
 SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                  -e s/arm.*/arm/ -e s/sa110/arm/ \
                                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
-                                 -e s/ppc64/powerpc/ )
+                                 -e s/ppc.*/powerpc/ )
 
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
index 50b9afa8ae6d09cbb9655cb5654d04dc7ec162e9..5959e36c3b4c52ba2eaeaedf8afe9ecced20c3f2 100644 (file)
@@ -180,6 +180,7 @@ config ARCH_OMAP
 config ARCH_VERSATILE
        bool "Versatile"
        select ARM_AMBA
+       select ARM_VIC
        select ICST307
        help
          This enables support for ARM Ltd Versatile board.
@@ -400,6 +401,38 @@ config NO_IDLE_HZ
          Currently at least OMAP, PXA2xx and SA11x0 platforms are known
          to have accurate timekeeping with dynamic tick.
 
+config AEABI
+       bool "Use the ARM EABI to compile the kernel"
+       help
+         This option allows for the kernel to be compiled using the latest
+         ARM ABI (aka EABI).  This is only useful if you are using a user
+         space environment that is also compiled with EABI.
+
+         Since there are major incompatibilities between the legacy ABI and
+         EABI, especially with regard to structure member alignment, this
+         option also changes the kernel syscall calling convention to
+         disambiguate both ABIs and allow for backward compatibility support
+         (selected with CONFIG_OABI_COMPAT).
+
+         To use this you need GCC version 4.0.0 or later.
+
+config OABI_COMPAT
+       bool "Allow old ABI binaries to run with this kernel"
+       depends on AEABI
+       default y
+       help
+         This option preserves the old syscall interface along with the
+         new (ARM EABI) one. It also provides a compatibility layer to
+         intercept syscalls that have structure arguments which layout
+         in memory differs between the legacy ABI and the new ARM EABI
+         (only for non "thumb" binaries). This option adds a tiny
+         overhead to all syscalls and produces a slightly larger kernel.
+         If you know you'll be using only pure EABI user space then you
+         can say N here. If this option is not selected and you attempt
+         to execute a legacy ABI binary then the result will be
+         UNPREDICTABLE (in fact it can be predicted that it won't work
+         at all). If in doubt say Y.
+
 config ARCH_DISCONTIGMEM_ENABLE
        bool
        default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
@@ -586,6 +619,7 @@ comment "At least one emulation must be selected"
 
 config FPE_NWFPE
        bool "NWFPE math emulation"
+       depends on !AEABI || OABI_COMPAT
        ---help---
          Say Y to include the NWFPE floating point emulator in the kernel.
          This is necessary to run most binaries. Linux does not currently
@@ -609,7 +643,7 @@ config FPE_NWFPE_XP
 
 config FPE_FASTFPE
        bool "FastFPE math emulation (EXPERIMENTAL)"
-       depends on !CPU_32v3 && EXPERIMENTAL
+       depends on (!AEABI || OABI_COMPAT) && !CPU_32v3 && EXPERIMENTAL
        ---help---
          Say Y here to include the FAST floating point emulator in the kernel.
          This is an experimental much faster emulator which now also has full
@@ -641,6 +675,7 @@ source "fs/Kconfig.binfmt"
 
 config ARTHUR
        tristate "RISC OS personality"
+       depends on !AEABI
        help
          Say Y here to include the kernel code necessary if you want to run
          Acorn RISC OS/Arthur binaries under Linux. This code is still very
@@ -729,6 +764,8 @@ source "drivers/char/Kconfig"
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/spi/Kconfig"
+
 source "drivers/hwmon/Kconfig"
 
 #source "drivers/l3/Kconfig"
index 1fa2a1011584574c9f1ef9697145ee955d98216b..fbfc14a56b965a9ed20f1bda358b6ebc37d43088 100644 (file)
@@ -56,8 +56,13 @@ tune-$(CONFIG_CPU_SA1100)    :=-mtune=strongarm1100
 tune-$(CONFIG_CPU_XSCALE)      :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
 tune-$(CONFIG_CPU_V6)          :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
 
-# Need -Uarm for gcc < 3.x
+ifeq ($(CONFIG_AEABI),y)
+CFLAGS_ABI     :=-mabi=aapcs -mno-thumb-interwork
+else
 CFLAGS_ABI     :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
+endif
+
+# Need -Uarm for gcc < 3.x
 CFLAGS         +=$(CFLAGS_ABI) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
 AFLAGS         +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float
 
index d7509c7a3c5e651a2634ea04f203aca8a5226f4f..5e34ca6d38b6de3132527ffae59904c99b25a7e5 100644 (file)
@@ -1,7 +1,10 @@
-config ICST525
+config ARM_GIC
        bool
 
-config ARM_GIC
+config ARM_VIC
+       bool
+
+config ICST525
        bool
 
 config ICST307
index ec8d17c96906aac4819918799ed9296be6008c05..c81a2ff6b5be35a5541dd7eabc94416023322b92 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-y                          += rtctime.o
 obj-$(CONFIG_ARM_GIC)          += gic.o
+obj-$(CONFIG_ARM_VIC)          += vic.o
 obj-$(CONFIG_ICST525)          += icst525.o
 obj-$(CONFIG_ICST307)          += icst307.o
 obj-$(CONFIG_SA1111)           += sa1111.o
index 1b7eaab02b9ec66263b0c66cd15e4522ab72f06f..159ad7ed7a40142c16093588fb0988963c675b29 100644 (file)
@@ -1103,14 +1103,14 @@ static int locomo_bus_remove(struct device *dev)
 struct bus_type locomo_bus_type = {
        .name           = "locomo-bus",
        .match          = locomo_match,
+       .probe          = locomo_bus_probe,
+       .remove         = locomo_bus_remove,
        .suspend        = locomo_bus_suspend,
        .resume         = locomo_bus_resume,
 };
 
 int locomo_driver_register(struct locomo_driver *driver)
 {
-       driver->drv.probe = locomo_bus_probe;
-       driver->drv.remove = locomo_bus_remove;
        driver->drv.bus = &locomo_bus_type;
        return driver_register(&driver->drv);
 }
index d0d6e6d2d649e9887813fc6f3e08debb292e2b81..1475089f9b4265f7b2c9dc86696dea0a4970c027 100644 (file)
@@ -1247,14 +1247,14 @@ static int sa1111_bus_remove(struct device *dev)
 struct bus_type sa1111_bus_type = {
        .name           = "sa1111-rab",
        .match          = sa1111_match,
+       .probe          = sa1111_bus_probe,
+       .remove         = sa1111_bus_remove,
        .suspend        = sa1111_bus_suspend,
        .resume         = sa1111_bus_resume,
 };
 
 int sa1111_driver_register(struct sa1111_driver *driver)
 {
-       driver->drv.probe = sa1111_bus_probe;
-       driver->drv.remove = sa1111_bus_remove;
        driver->drv.bus = &sa1111_bus_type;
        return driver_register(&driver->drv);
 }
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
new file mode 100644 (file)
index 0000000..a45ed16
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  linux/arch/arm/common/vic.c
+ *
+ *  Copyright (C) 1999 - 2003 ARM Limited
+ *  Copyright (C) 2000 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 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/list.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/hardware/vic.h>
+
+static void __iomem *vic_base;
+
+static void vic_mask_irq(unsigned int irq)
+{
+       irq -= IRQ_VIC_START;
+       writel(1 << irq, vic_base + VIC_INT_ENABLE_CLEAR);
+}
+
+static void vic_unmask_irq(unsigned int irq)
+{
+       irq -= IRQ_VIC_START;
+       writel(1 << irq, vic_base + VIC_INT_ENABLE);
+}
+
+static struct irqchip vic_chip = {
+       .ack    = vic_mask_irq,
+       .mask   = vic_mask_irq,
+       .unmask = vic_unmask_irq,
+};
+
+void __init vic_init(void __iomem *base, u32 vic_sources)
+{
+       unsigned int i;
+
+       vic_base = base;
+
+       /* Disable all interrupts initially. */
+
+       writel(0, vic_base + VIC_INT_SELECT);
+       writel(0, vic_base + VIC_INT_ENABLE);
+       writel(~0, vic_base + VIC_INT_ENABLE_CLEAR);
+       writel(0, vic_base + VIC_IRQ_STATUS);
+       writel(0, vic_base + VIC_ITCR);
+       writel(~0, vic_base + VIC_INT_SOFT_CLEAR);
+
+       /*
+        * Make sure we clear all existing interrupts
+        */
+       writel(0, vic_base + VIC_VECT_ADDR);
+       for (i = 0; i < 19; i++) {
+               unsigned int value;
+
+               value = readl(vic_base + VIC_VECT_ADDR);
+               writel(value, vic_base + VIC_VECT_ADDR);
+       }
+
+       for (i = 0; i < 16; i++) {
+               void __iomem *reg = vic_base + VIC_VECT_CNTL0 + (i * 4);
+               writel(VIC_VECT_CNTL_ENABLE | i, reg);
+       }
+
+       writel(32, vic_base + VIC_DEF_VECT_ADDR);
+
+       for (i = 0; i < 32; i++) {
+               unsigned int irq = IRQ_VIC_START + i;
+
+               set_irq_chip(irq, &vic_chip);
+
+               if (vic_sources & (1 << i)) {
+                       set_irq_handler(irq, do_level_IRQ);
+                       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+               }
+       }
+}
index de94b0f3ee2a658c8ced0c87d9460ca4f2e0f1ac..2ce0e3a27a4545d9817eed1d602fee3adec34da7 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_ARTHUR)          += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
 obj-$(CONFIG_PCI)              += bios32.o
 obj-$(CONFIG_SMP)              += smp.o
+obj-$(CONFIG_OABI_COMPAT)      += sys_oabi-compat.o
 
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
index 9997098009a9941ff63c025c23be09aa56b6ccbf..1574941ebfe187f75f46df9de64fe905739b6747 100644 (file)
@@ -35,6 +35,16 @@ extern void __udivsi3(void);
 extern void __umodsi3(void);
 extern void __do_div64(void);
 
+extern void __aeabi_idiv(void);
+extern void __aeabi_idivmod(void);
+extern void __aeabi_lasr(void);
+extern void __aeabi_llsl(void);
+extern void __aeabi_llsr(void);
+extern void __aeabi_lmul(void);
+extern void __aeabi_uidiv(void);
+extern void __aeabi_uidivmod(void);
+extern void __aeabi_ulcmp(void);
+
 extern void fpundefinstr(void);
 extern void fp_enter(void);
 
@@ -141,6 +151,18 @@ EXPORT_SYMBOL(__udivsi3);
 EXPORT_SYMBOL(__umodsi3);
 EXPORT_SYMBOL(__do_div64);
 
+#ifdef CONFIG_AEABI
+EXPORT_SYMBOL(__aeabi_idiv);
+EXPORT_SYMBOL(__aeabi_idivmod);
+EXPORT_SYMBOL(__aeabi_lasr);
+EXPORT_SYMBOL(__aeabi_llsl);
+EXPORT_SYMBOL(__aeabi_llsr);
+EXPORT_SYMBOL(__aeabi_lmul);
+EXPORT_SYMBOL(__aeabi_uidiv);
+EXPORT_SYMBOL(__aeabi_uidivmod);
+EXPORT_SYMBOL(__aeabi_ulcmp);
+#endif
+
        /* bitops */
 EXPORT_SYMBOL(_set_bit_le);
 EXPORT_SYMBOL(_test_and_set_bit_le);
index 55076a75e5bf3794de942c7f7abe3e1993bfb18e..75e6f9a947133b5d2768cf8aa9ab73f1488e3625 100644 (file)
@@ -13,7 +13,7 @@
 #define NR_syscalls 328
 #else
 
-__syscall_start:
+100:
 /* 0 */                .long   sys_restart_syscall
                .long   sys_exit
                .long   sys_fork_wrapper
@@ -27,7 +27,7 @@ __syscall_start:
 /* 10 */       .long   sys_unlink
                .long   sys_execve_wrapper
                .long   sys_chdir
-               .long   sys_time                /* used by libc4 */
+               .long   OBSOLETE(sys_time)      /* used by libc4 */
                .long   sys_mknod
 /* 15 */       .long   sys_chmod
                .long   sys_lchown16
@@ -36,15 +36,15 @@ __syscall_start:
                .long   sys_lseek
 /* 20 */       .long   sys_getpid
                .long   sys_mount
-               .long   sys_oldumount           /* used by libc4 */
+               .long   OBSOLETE(sys_oldumount) /* used by libc4 */
                .long   sys_setuid16
                .long   sys_getuid16
-/* 25 */       .long   sys_stime
+/* 25 */       .long   OBSOLETE(sys_stime)
                .long   sys_ptrace
-               .long   sys_alarm               /* used by libc4 */
+               .long   OBSOLETE(sys_alarm)     /* used by libc4 */
                .long   sys_ni_syscall          /* was sys_fstat */
                .long   sys_pause
-/* 30 */       .long   sys_utime               /* used by libc4 */
+/* 30 */       .long   OBSOLETE(sys_utime)     /* used by libc4 */
                .long   sys_ni_syscall          /* was sys_stty */
                .long   sys_ni_syscall          /* was sys_getty */
                .long   sys_access
@@ -90,21 +90,21 @@ __syscall_start:
                .long   sys_sigpending
                .long   sys_sethostname
 /* 75 */       .long   sys_setrlimit
-               .long   sys_old_getrlimit       /* used by libc4 */
+               .long   OBSOLETE(sys_old_getrlimit) /* used by libc4 */
                .long   sys_getrusage
                .long   sys_gettimeofday
                .long   sys_settimeofday
 /* 80 */       .long   sys_getgroups16
                .long   sys_setgroups16
-               .long   old_select              /* used by libc4 */
+               .long   OBSOLETE(old_select)    /* used by libc4 */
                .long   sys_symlink
                .long   sys_ni_syscall          /* was sys_lstat */
 /* 85 */       .long   sys_readlink
                .long   sys_uselib
                .long   sys_swapon
                .long   sys_reboot
-               .long   old_readdir             /* used by libc4 */
-/* 90 */       .long   old_mmap                /* used by libc4 */
+               .long   OBSOLETE(old_readdir)   /* used by libc4 */
+/* 90 */       .long   OBSOLETE(old_mmap)      /* used by libc4 */
                .long   sys_munmap
                .long   sys_truncate
                .long   sys_ftruncate
@@ -116,7 +116,7 @@ __syscall_start:
                .long   sys_statfs
 /* 100 */      .long   sys_fstatfs
                .long   sys_ni_syscall
-               .long   sys_socketcall
+               .long   OBSOLETE(sys_socketcall)
                .long   sys_syslog
                .long   sys_setitimer
 /* 105 */      .long   sys_getitimer
@@ -127,11 +127,11 @@ __syscall_start:
 /* 110 */      .long   sys_ni_syscall          /* was sys_iopl */
                .long   sys_vhangup
                .long   sys_ni_syscall
-               .long   sys_syscall             /* call a syscall */
+               .long   OBSOLETE(sys_syscall)   /* call a syscall */
                .long   sys_wait4
 /* 115 */      .long   sys_swapoff
                .long   sys_sysinfo
-               .long   sys_ipc
+               .long   OBSOLETE(ABI(sys_ipc, sys_oabi_ipc))
                .long   sys_fsync
                .long   sys_sigreturn_wrapper
 /* 120 */      .long   sys_clone_wrapper
@@ -194,8 +194,8 @@ __syscall_start:
                .long   sys_rt_sigtimedwait
                .long   sys_rt_sigqueueinfo
                .long   sys_rt_sigsuspend_wrapper
-/* 180 */      .long   sys_pread64
-               .long   sys_pwrite64
+/* 180 */      .long   ABI(sys_pread64, sys_oabi_pread64)
+               .long   ABI(sys_pwrite64, sys_oabi_pwrite64)
                .long   sys_chown16
                .long   sys_getcwd
                .long   sys_capget
@@ -207,11 +207,11 @@ __syscall_start:
 /* 190 */      .long   sys_vfork_wrapper
                .long   sys_getrlimit
                .long   sys_mmap2
-               .long   sys_truncate64
-               .long   sys_ftruncate64
-/* 195 */      .long   sys_stat64
-               .long   sys_lstat64
-               .long   sys_fstat64
+               .long   ABI(sys_truncate64, sys_oabi_truncate64)
+               .long   ABI(sys_ftruncate64, sys_oabi_ftruncate64)
+/* 195 */      .long   ABI(sys_stat64, sys_oabi_stat64)
+               .long   ABI(sys_lstat64, sys_oabi_lstat64)
+               .long   ABI(sys_fstat64, sys_oabi_fstat64)
                .long   sys_lchown
                .long   sys_getuid
 /* 200 */      .long   sys_getgid
@@ -235,11 +235,11 @@ __syscall_start:
                .long   sys_pivot_root
                .long   sys_mincore
 /* 220 */      .long   sys_madvise
-               .long   sys_fcntl64
+               .long   ABI(sys_fcntl64, sys_oabi_fcntl64)
                .long   sys_ni_syscall /* TUX */
                .long   sys_ni_syscall
                .long   sys_gettid
-/* 225 */      .long   sys_readahead
+/* 225 */      .long   ABI(sys_readahead, sys_oabi_readahead)
                .long   sys_setxattr
                .long   sys_lsetxattr
                .long   sys_fsetxattr
@@ -265,8 +265,8 @@ __syscall_start:
                .long   sys_exit_group
                .long   sys_lookup_dcookie
 /* 250 */      .long   sys_epoll_create
-               .long   sys_epoll_ctl
-               .long   sys_epoll_wait
+               .long   ABI(sys_epoll_ctl, sys_oabi_epoll_ctl)
+               .long   ABI(sys_epoll_wait, sys_oabi_epoll_wait)
                .long   sys_remap_file_pages
                .long   sys_ni_syscall  /* sys_set_thread_area */
 /* 255 */      .long   sys_ni_syscall  /* sys_get_thread_area */
@@ -280,8 +280,8 @@ __syscall_start:
                .long   sys_clock_gettime
                .long   sys_clock_getres
 /* 265 */      .long   sys_clock_nanosleep
-               .long   sys_statfs64
-               .long   sys_fstatfs64
+               .long   sys_statfs64_wrapper
+               .long   sys_fstatfs64_wrapper
                .long   sys_tgkill
                .long   sys_utimes
 /* 270 */      .long   sys_arm_fadvise64_64
@@ -312,7 +312,7 @@ __syscall_start:
 /* 295 */      .long   sys_getsockopt
                .long   sys_sendmsg
                .long   sys_recvmsg
-               .long   sys_semop
+               .long   ABI(sys_semop, sys_oabi_semop)
                .long   sys_semget
 /* 300 */      .long   sys_semctl
                .long   sys_msgsnd
@@ -326,7 +326,7 @@ __syscall_start:
                .long   sys_add_key
 /* 310 */      .long   sys_request_key
                .long   sys_keyctl
-               .long   sys_semtimedop
+               .long   ABI(sys_semtimedop, sys_oabi_semtimedop)
 /* vserver */  .long   sys_ni_syscall
                .long   sys_ioprio_set
 /* 315 */      .long   sys_ioprio_get
@@ -336,9 +336,8 @@ __syscall_start:
                .long   sys_mbind
 /* 320 */      .long   sys_get_mempolicy
                .long   sys_set_mempolicy
-__syscall_end:
 
-               .rept   NR_syscalls - (__syscall_end - __syscall_start) / 4
+               .rept   NR_syscalls - (. - 100b) / 4
                        .long   sys_ni_syscall
                .endr
 #endif
index 96fd91926c9bde875173dab2b95f50dbfe13b69c..74ea29c3205eb6b476a2c725858bf70895f9288f 100644 (file)
@@ -1147,9 +1147,11 @@ static void ecard_drv_shutdown(struct device *dev)
        struct ecard_driver *drv = ECARD_DRV(dev->driver);
        struct ecard_request req;
 
-       if (drv->shutdown)
-               drv->shutdown(ec);
-       ecard_release(ec);
+       if (dev->driver) {
+               if (drv->shutdown)
+                       drv->shutdown(ec);
+               ecard_release(ec);
+       }
 
        /*
         * If this card has a loader, call the reset handler.
@@ -1164,9 +1166,6 @@ static void ecard_drv_shutdown(struct device *dev)
 int ecard_register_driver(struct ecard_driver *drv)
 {
        drv->drv.bus = &ecard_bus_type;
-       drv->drv.probe = ecard_drv_probe;
-       drv->drv.remove = ecard_drv_remove;
-       drv->drv.shutdown = ecard_drv_shutdown;
 
        return driver_register(&drv->drv);
 }
@@ -1195,6 +1194,9 @@ struct bus_type ecard_bus_type = {
        .name           = "ecard",
        .dev_attrs      = ecard_dev_attrs,
        .match          = ecard_match,
+       .probe          = ecard_drv_probe,
+       .remove         = ecard_drv_remove,
+       .shutdown       = ecard_drv_shutdown,
 };
 
 static int ecard_bus_init(void)
index a52baedf6262f776c2b2be8a474efc5290c0f7c9..874e6bb7940578fd86878e69ae9ddc7b91eee03f 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1996,1997,1998 Russell King.
  *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
+ *  nommu support by Hyok S. Choi (hyok.choi@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
@@ -104,14 +105,24 @@ common_invalid:
 /*
  * SVC mode handlers
  */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define SPFIX(code...) code
+#else
+#define SPFIX(code...)
+#endif
+
        .macro  svc_entry
        sub     sp, sp, #S_FRAME_SIZE
+ SPFIX(        tst     sp, #4          )
+ SPFIX(        bicne   sp, sp, #4      )
        stmib   sp, {r1 - r12}
 
        ldmia   r0, {r1 - r3}
        add     r5, sp, #S_SP           @ here for interlock avoidance
        mov     r4, #-1                 @  ""  ""      ""       ""
        add     r0, sp, #S_FRAME_SIZE   @  ""  ""      ""       ""
+ SPFIX(        addne   r0, r0, #4      )
        str     r1, [sp]                @ save the "real" r0 copied
                                        @ from the exception stack
 
@@ -302,7 +313,14 @@ __pabt_svc:
 
 /*
  * User mode handlers
+ *
+ * EABI note: sp_svc is always 64-bit aligned here, so should S_FRAME_SIZE
  */
+
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
+#error "sizeof(struct pt_regs) must be a multiple of 8"
+#endif
+
        .macro  usr_entry
        sub     sp, sp, #S_FRAME_SIZE
        stmib   sp, {r1 - r12}
@@ -538,7 +556,11 @@ ENTRY(__switch_to)
        add     ip, r1, #TI_CPU_SAVE
        ldr     r3, [r2, #TI_TP_VALUE]
        stmia   ip!, {r4 - sl, fp, sp, lr}      @ Store most regs on stack
+#ifndef CONFIG_MMU
+       add     r2, r2, #TI_CPU_DOMAIN
+#else
        ldr     r6, [r2, #TI_CPU_DOMAIN]!
+#endif
 #if __LINUX_ARM_ARCH__ >= 6
 #ifdef CONFIG_CPU_MPCORE
        clrex
@@ -556,7 +578,9 @@ ENTRY(__switch_to)
        mov     r4, #0xffff0fff
        str     r3, [r4, #-15]                  @ TLS val at 0xffff0ff0
 #endif
+#ifdef CONFIG_MMU
        mcr     p15, 0, r6, c3, c0, 0           @ Set domain register
+#endif
 #ifdef CONFIG_VFP
        @ Always disable VFP so we can lazily save/restore the old
        @ state. This occurs in the context of the previous thread.
index e2b42997ad33ee0f1da6ec4a75440d16ce3c3b06..2b92ce85f97feef93415fd25c9260afa6367a6ae 100644 (file)
@@ -98,20 +98,14 @@ ENTRY(ret_from_fork)
           run on an ARM7 and we can save a couple of instructions.  
                                                                --pb */
 #ifdef CONFIG_CPU_ARM710
-       .macro  arm710_bug_check, instr, temp
-       and     \temp, \instr, #0x0f000000      @ check for SWI
-       teq     \temp, #0x0f000000
-       bne     .Larm700bug
-       .endm
-
-.Larm700bug:
+#define A710(code...) code
+.Larm710bug:
        ldmia   sp, {r0 - lr}^                  @ Get calling r0 - lr
        mov     r0, r0
        add     sp, sp, #S_FRAME_SIZE
        subs    pc, lr, #4
 #else
-       .macro  arm710_bug_check, instr, temp
-       .endm
+#define A710(code...)
 #endif
 
        .align  5
@@ -129,14 +123,50 @@ ENTRY(vector_swi)
        /*
         * Get the system call number.
         */
+
+#if defined(CONFIG_OABI_COMPAT)
+
+       /*
+        * If we have CONFIG_OABI_COMPAT then we need to look at the swi
+        * value to determine if it is an EABI or an old ABI call.
+        */
 #ifdef CONFIG_ARM_THUMB
+       tst     r8, #PSR_T_BIT
+       movne   r10, #0                         @ no thumb OABI emulation
+       ldreq   r10, [lr, #-4]                  @ get SWI instruction
+#else
+       ldr     r10, [lr, #-4]                  @ get SWI instruction
+  A710(        and     ip, r10, #0x0f000000            @ check for SWI         )
+  A710(        teq     ip, #0x0f000000                                         )
+  A710(        bne     .Larm710bug                                             )
+#endif
+
+#elif defined(CONFIG_AEABI)
+
+       /*
+        * Pure EABI user space always put syscall number into scno (r7).
+        */
+  A710(        ldr     ip, [lr, #-4]                   @ get SWI instruction   )
+  A710(        and     ip, ip, #0x0f000000             @ check for SWI         )
+  A710(        teq     ip, #0x0f000000                                         )
+  A710(        bne     .Larm710bug                                             )
+
+#elif defined(CONFIG_ARM_THUMB)
+
+       /* Legacy ABI only, possibly thumb mode. */
        tst     r8, #PSR_T_BIT                  @ this is SPSR from save_user_regs
        addne   scno, r7, #__NR_SYSCALL_BASE    @ put OS number in
        ldreq   scno, [lr, #-4]
+
 #else
+
+       /* Legacy ABI only. */
        ldr     scno, [lr, #-4]                 @ get SWI instruction
+  A710(        and     ip, scno, #0x0f000000           @ check for SWI         )
+  A710(        teq     ip, #0x0f000000                                         )
+  A710(        bne     .Larm710bug                                             )
+
 #endif
-       arm710_bug_check scno, ip
 
 #ifdef CONFIG_ALIGNMENT_TRAP
        ldr     ip, __cr_alignment
@@ -145,18 +175,31 @@ ENTRY(vector_swi)
 #endif
        enable_irq
 
-       stmdb   sp!, {r4, r5}                   @ push fifth and sixth args
-
        get_thread_info tsk
+       adr     tbl, sys_call_table             @ load syscall table pointer
        ldr     ip, [tsk, #TI_FLAGS]            @ check for syscall tracing
+
+#if defined(CONFIG_OABI_COMPAT)
+       /*
+        * If the swi argument is zero, this is an EABI call and we do nothing.
+        *
+        * If this is an old ABI call, get the syscall number into scno and
+        * get the old ABI syscall table address.
+        */
+       bics    r10, r10, #0xff000000
+       eorne   scno, r10, #__NR_OABI_SYSCALL_BASE
+       ldrne   tbl, =sys_oabi_call_table
+#elif !defined(CONFIG_AEABI)
        bic     scno, scno, #0xff000000         @ mask off SWI op-code
        eor     scno, scno, #__NR_SYSCALL_BASE  @ check OS number
-       adr     tbl, sys_call_table             @ load syscall table pointer
+#endif
+
+       stmdb   sp!, {r4, r5}                   @ push fifth and sixth args
        tst     ip, #_TIF_SYSCALL_TRACE         @ are we tracing syscalls?
        bne     __sys_trace
 
-       adr     lr, ret_fast_syscall            @ return address
        cmp     scno, #NR_syscalls              @ check upper syscall limit
+       adr     lr, ret_fast_syscall            @ return address
        ldrcc   pc, [tbl, scno, lsl #2]         @ call sys_* routine
 
        add     r1, sp, #S_OFF
@@ -171,11 +214,13 @@ ENTRY(vector_swi)
         * context switches, and waiting for our parent to respond.
         */
 __sys_trace:
+       mov     r2, scno
        add     r1, sp, #S_OFF
        mov     r0, #0                          @ trace entry [IP = 0]
        bl      syscall_trace
 
        adr     lr, __sys_trace_return          @ return address
+       mov     scno, r0                        @ syscall number (possibly new)
        add     r1, sp, #S_R0 + S_OFF           @ pointer to regs
        cmp     scno, #NR_syscalls              @ check upper syscall limit
        ldmccia r1, {r0 - r3}                   @ have to reload r0 - r3
@@ -184,6 +229,7 @@ __sys_trace:
 
 __sys_trace_return:
        str     r0, [sp, #S_R0 + S_OFF]!        @ save returned r0
+       mov     r2, scno
        mov     r1, sp
        mov     r0, #1                          @ trace exit [IP = 1]
        bl      syscall_trace
@@ -194,11 +240,25 @@ __sys_trace_return:
        .type   __cr_alignment, #object
 __cr_alignment:
        .word   cr_alignment
+#endif
+       .ltorg
+
+/*
+ * This is the syscall table declaration for native ABI syscalls.
+ * With EABI a couple syscalls are obsolete and defined as sys_ni_syscall.
+ */
+#define ABI(native, compat) native
+#ifdef CONFIG_AEABI
+#define OBSOLETE(syscall) sys_ni_syscall
+#else
+#define OBSOLETE(syscall) syscall
 #endif
 
        .type   sys_call_table, #object
 ENTRY(sys_call_table)
 #include "calls.S"
+#undef ABI
+#undef OBSOLETE
 
 /*============================================================================
  * Special system call wrappers
@@ -207,7 +267,7 @@ ENTRY(sys_call_table)
 @ r8 = syscall table
                .type   sys_syscall, #function
 sys_syscall:
-               eor     scno, r0, #__NR_SYSCALL_BASE
+               eor     scno, r0, #__NR_OABI_SYSCALL_BASE
                cmp     scno, #__NR_syscall - __NR_SYSCALL_BASE
                cmpne   scno, #NR_syscalls      @ check range
                stmloia sp, {r5, r6}            @ shuffle args
@@ -255,6 +315,16 @@ sys_sigaltstack_wrapper:
                ldr     r2, [sp, #S_OFF + S_SP]
                b       do_sigaltstack
 
+sys_statfs64_wrapper:
+               teq     r1, #88
+               moveq   r1, #84
+               b       sys_statfs64
+
+sys_fstatfs64_wrapper:
+               teq     r1, #88
+               moveq   r1, #84
+               b       sys_fstatfs64
+
 /*
  * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
  * offset, we return EINVAL.
@@ -271,3 +341,49 @@ sys_mmap2:
                str     r5, [sp, #4]
                b       do_mmap2
 #endif
+
+#ifdef CONFIG_OABI_COMPAT
+
+/*
+ * These are syscalls with argument register differences
+ */
+
+sys_oabi_pread64:
+               stmia   sp, {r3, r4}
+               b       sys_pread64
+
+sys_oabi_pwrite64:
+               stmia   sp, {r3, r4}
+               b       sys_pwrite64
+
+sys_oabi_truncate64:
+               mov     r3, r2
+               mov     r2, r1
+               b       sys_truncate64
+
+sys_oabi_ftruncate64:
+               mov     r3, r2
+               mov     r2, r1
+               b       sys_ftruncate64
+
+sys_oabi_readahead:
+               str     r3, [sp]
+               mov     r3, r2
+               mov     r2, r1
+               b       sys_readahead
+
+/*
+ * Let's declare a second syscall table for old ABI binaries
+ * using the compatibility syscall entries.
+ */
+#define ABI(native, compat) compat
+#define OBSOLETE(syscall) syscall
+
+       .type   sys_oabi_call_table, #object
+ENTRY(sys_oabi_call_table)
+#include "calls.S"
+#undef ABI
+#undef OBSOLETE
+
+#endif
+
index 648cfff93138bdc1df9e025efef31dbc1211a821..55c99cdab7d64f430f1e3063343111cfdf9dfce9 100644 (file)
@@ -19,6 +19,7 @@
 @
 @ Most of the stack format comes from struct pt_regs, but with
 @ the addition of 8 bytes for storing syscall args 5 and 6.
+@ This _must_ remain a multiple of 8 for EABI.
 @
 #define S_OFF          8
 
index 1e985f2cd70fc4ab0df4dfa07616d9204b6fa87a..1aca1775b28f188ac6682e5dfd15cd54e05b414e 100644 (file)
@@ -251,12 +251,11 @@ __turn_mmu_on:
  * r10 = procinfo
  *
  * Returns:
- *  r0, r3, r5, r6, r7 corrupted
+ *  r0, r3, r6, r7 corrupted
  *  r4 = physical page table address
  */
        .type   __create_page_tables, %function
 __create_page_tables:
-       ldr     r5, [r8, #MACHINFO_PHYSRAM]     @ physram
        pgtbl   r4                              @ page table address
 
        /*
@@ -303,7 +302,7 @@ __create_page_tables:
         * Then map first 1MB of ram in case it contains our boot params.
         */
        add     r0, r4, #PAGE_OFFSET >> 18
-       orr     r6, r5, r7
+       orr     r6, r7, #PHYS_OFFSET
        str     r6, [r0]
 
 #ifdef CONFIG_XIP_KERNEL
@@ -311,7 +310,7 @@ __create_page_tables:
         * Map some ram to cover our .data and .bss areas.
         * Mapping 3MB should be plenty.
         */
-       sub     r3, r4, r5
+       sub     r3, r4, #PHYS_OFFSET
        mov     r3, r3, lsr #20
        add     r0, r0, r3, lsl #2
        add     r6, r6, r3, lsl #20
index e591f72bcdeb0abf8d6714e94219de4cdc2d7720..7b6256bb590ed4ddc90a2300ddf3d7299452c016 100644 (file)
@@ -766,6 +766,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                       (unsigned long __user *) data);
                        break;
 
+               case PTRACE_SET_SYSCALL:
+                       ret = 0;
+                       child->ptrace_message = data;
+                       break;
+
                default:
                        ret = ptrace_request(child, request, addr, data);
                        break;
@@ -774,14 +779,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        return ret;
 }
 
-asmlinkage void syscall_trace(int why, struct pt_regs *regs)
+asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
 {
        unsigned long ip;
 
        if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
+               return scno;
        if (!(current->ptrace & PT_PTRACED))
-               return;
+               return scno;
 
        /*
         * Save IP.  IP is used to denote syscall entry/exit:
@@ -790,6 +795,8 @@ asmlinkage void syscall_trace(int why, struct pt_regs *regs)
        ip = regs->ARM_ip;
        regs->ARM_ip = why;
 
+       current->ptrace_message = scno;
+
        /* 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)
@@ -804,4 +811,6 @@ asmlinkage void syscall_trace(int why, struct pt_regs *regs)
                current->exit_code = 0;
        }
        regs->ARM_ip = ip;
+
+       return current->ptrace_message;
 }
index 4c31f292305563bbf5199460a75df12f6475c5f9..981fe5c6ccbed40575950bb6c71cb6fbc8f53c34 100644 (file)
@@ -177,41 +177,42 @@ int __down_trylock(struct semaphore * sem)
  * ip contains the semaphore pointer on entry. Save the C-clobbered
  * registers (r0 to r3 and lr), but not ip, as we use it as a return
  * value in some cases..
+ * To remain AAPCS compliant (64-bit stack align) we save r4 as well.
  */
 asm("  .section .sched.text,\"ax\",%progbits   \n\
        .align  5                               \n\
        .globl  __down_failed                   \n\
 __down_failed:                                 \n\
-       stmfd   sp!, {r0 - r3, lr}              \n\
+       stmfd   sp!, {r0 - r4, lr}              \n\
        mov     r0, ip                          \n\
        bl      __down                          \n\
-       ldmfd   sp!, {r0 - r3, pc}              \n\
+       ldmfd   sp!, {r0 - r4, pc}              \n\
                                                \n\
        .align  5                               \n\
        .globl  __down_interruptible_failed     \n\
 __down_interruptible_failed:                   \n\
-       stmfd   sp!, {r0 - r3, lr}              \n\
+       stmfd   sp!, {r0 - r4, lr}              \n\
        mov     r0, ip                          \n\
        bl      __down_interruptible            \n\
        mov     ip, r0                          \n\
-       ldmfd   sp!, {r0 - r3, pc}              \n\
+       ldmfd   sp!, {r0 - r4, pc}              \n\
                                                \n\
        .align  5                               \n\
        .globl  __down_trylock_failed           \n\
 __down_trylock_failed:                         \n\
-       stmfd   sp!, {r0 - r3, lr}              \n\
+       stmfd   sp!, {r0 - r4, lr}              \n\
        mov     r0, ip                          \n\
        bl      __down_trylock                  \n\
        mov     ip, r0                          \n\
-       ldmfd   sp!, {r0 - r3, pc}              \n\
+       ldmfd   sp!, {r0 - r4, pc}              \n\
                                                \n\
        .align  5                               \n\
        .globl  __up_wakeup                     \n\
 __up_wakeup:                                   \n\
-       stmfd   sp!, {r0 - r3, lr}              \n\
+       stmfd   sp!, {r0 - r4, lr}              \n\
        mov     r0, ip                          \n\
        bl      __up                            \n\
-       ldmfd   sp!, {r0 - r3, pc}              \n\
+       ldmfd   sp!, {r0 - r4, pc}              \n\
        ");
 
 EXPORT_SYMBOL(__down_failed);
index ea569ba482b165bd05292ea3504c3d90bbeab04c..a491de2d9024dcb8b248f2ec7364012b4beef3de 100644 (file)
@@ -147,6 +147,7 @@ asmlinkage int old_select(struct sel_arg_struct __user *arg)
        return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
 }
 
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
  *
@@ -226,6 +227,7 @@ asmlinkage int sys_ipc(uint call, int first, int second, int third,
                return -ENOSYS;
        }
 }
+#endif
 
 /* Fork a new task - this creates a new program thread.
  * This is called indirectly via a small wrapper
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
new file mode 100644 (file)
index 0000000..eafa8e5
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ *  arch/arm/kernel/sys_oabi-compat.c
+ *
+ *  Compatibility wrappers for syscalls that are used from
+ *  old ABI user space binaries with an EABI kernel.
+ *
+ *  Author:    Nicolas Pitre
+ *  Created:   Oct 7, 2005
+ *  Copyright: 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.
+ */
+
+/*
+ * The legacy ABI and the new ARM EABI have different rules making some
+ * syscalls incompatible especially with structure arguments.
+ * Most notably, Eabi says 64-bit members should be 64-bit aligned instead of
+ * simply word aligned.  EABI also pads structures to the size of the largest
+ * member it contains instead of the invariant 32-bit.
+ *
+ * The following syscalls are affected:
+ *
+ * sys_stat64:
+ * sys_lstat64:
+ * sys_fstat64:
+ *
+ *   struct stat64 has different sizes and some members are shifted
+ *   Compatibility wrappers are needed for them and provided below.
+ *
+ * sys_fcntl64:
+ *
+ *   struct flock64 has different sizes and some members are shifted
+ *   A compatibility wrapper is needed and provided below.
+ *
+ * sys_statfs64:
+ * sys_fstatfs64:
+ *
+ *   struct statfs64 has extra padding with EABI growing its size from
+ *   84 to 88.  This struct is now __attribute__((packed,aligned(4)))
+ *   with a small assembly wrapper to force the sz argument to 84 if it is 88
+ *   to avoid copying the extra padding over user space unexpecting it.
+ *
+ * sys_newuname:
+ *
+ *   struct new_utsname has no padding with EABI.  No problem there.
+ *
+ * sys_epoll_ctl:
+ * sys_epoll_wait:
+ *
+ *   struct epoll_event has its second member shifted also affecting the
+ *   structure size. Compatibility wrappers are needed and provided below.
+ *
+ * sys_ipc:
+ * sys_semop:
+ * sys_semtimedop:
+ *
+ *   struct sembuf loses its padding with EABI.  Since arrays of them are
+ *   used they have to be copyed to remove the padding. Compatibility wrappers
+ *   provided below.
+ */
+
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/eventpoll.h>
+#include <linux/sem.h>
+#include <asm/ipc.h>
+#include <asm/uaccess.h>
+
+struct oldabi_stat64 {
+       unsigned long long st_dev;
+       unsigned int    __pad1;
+       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 int    __pad2;
+
+       long long       st_size;
+       unsigned long   st_blksize;
+       unsigned long long st_blocks;
+
+       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;
+} __attribute__ ((packed,aligned(4)));
+
+static long cp_oldabi_stat64(struct kstat *stat,
+                            struct oldabi_stat64 __user *statbuf)
+{
+       struct oldabi_stat64 tmp;
+
+       tmp.st_dev = huge_encode_dev(stat->dev);
+       tmp.__pad1 = 0;
+       tmp.__st_ino = stat->ino;
+       tmp.st_mode = stat->mode;
+       tmp.st_nlink = stat->nlink;
+       tmp.st_uid = stat->uid;
+       tmp.st_gid = stat->gid;
+       tmp.st_rdev = huge_encode_dev(stat->rdev);
+       tmp.st_size = stat->size;
+       tmp.st_blocks = stat->blocks;
+       tmp.__pad2 = 0;
+       tmp.st_blksize = stat->blksize;
+       tmp.st_atime = stat->atime.tv_sec;
+       tmp.st_atime_nsec = stat->atime.tv_nsec;
+       tmp.st_mtime = stat->mtime.tv_sec;
+       tmp.st_mtime_nsec = stat->mtime.tv_nsec;
+       tmp.st_ctime = stat->ctime.tv_sec;
+       tmp.st_ctime_nsec = stat->ctime.tv_nsec;
+       tmp.st_ino = stat->ino;
+       return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+}
+
+asmlinkage long sys_oabi_stat64(char __user * filename,
+                               struct oldabi_stat64 __user * statbuf)
+{
+       struct kstat stat;
+       int error = vfs_stat(filename, &stat);
+       if (!error)
+               error = cp_oldabi_stat64(&stat, statbuf);
+       return error;
+}
+
+asmlinkage long sys_oabi_lstat64(char __user * filename,
+                                struct oldabi_stat64 __user * statbuf)
+{
+       struct kstat stat;
+       int error = vfs_lstat(filename, &stat);
+       if (!error)
+               error = cp_oldabi_stat64(&stat, statbuf);
+       return error;
+}
+
+asmlinkage long sys_oabi_fstat64(unsigned long fd,
+                                struct oldabi_stat64 __user * statbuf)
+{
+       struct kstat stat;
+       int error = vfs_fstat(fd, &stat);
+       if (!error)
+               error = cp_oldabi_stat64(&stat, statbuf);
+       return error;
+}
+
+struct oabi_flock64 {
+       short   l_type;
+       short   l_whence;
+       loff_t  l_start;
+       loff_t  l_len;
+       pid_t   l_pid;
+} __attribute__ ((packed,aligned(4)));
+
+asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+                                unsigned long arg)
+{
+       struct oabi_flock64 user;
+       struct flock64 kernel;
+       mm_segment_t fs = USER_DS; /* initialized to kill a warning */
+       unsigned long local_arg = arg;
+       int ret;
+
+       switch (cmd) {
+       case F_GETLK64:
+       case F_SETLK64:
+       case F_SETLKW64:
+               if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
+                                  sizeof(user)))
+                       return -EFAULT;
+               kernel.l_type   = user.l_type;
+               kernel.l_whence = user.l_whence;
+               kernel.l_start  = user.l_start;
+               kernel.l_len    = user.l_len;
+               kernel.l_pid    = user.l_pid;
+               local_arg = (unsigned long)&kernel;
+               fs = get_fs();
+               set_fs(KERNEL_DS);
+       }
+
+       ret = sys_fcntl64(fd, cmd, local_arg);
+
+       switch (cmd) {
+       case F_GETLK64:
+               if (!ret) {
+                       user.l_type     = kernel.l_type;
+                       user.l_whence   = kernel.l_whence;
+                       user.l_start    = kernel.l_start;
+                       user.l_len      = kernel.l_len;
+                       user.l_pid      = kernel.l_pid;
+                       if (copy_to_user((struct oabi_flock64 __user *)arg,
+                                        &user, sizeof(user)))
+                               ret = -EFAULT;
+               }
+       case F_SETLK64:
+       case F_SETLKW64:
+               set_fs(fs);
+       }
+
+       return ret;
+}
+
+struct oabi_epoll_event {
+       __u32 events;
+       __u64 data;
+} __attribute__ ((packed,aligned(4)));
+
+asmlinkage long sys_oabi_epoll_ctl(int epfd, int op, int fd,
+                                  struct oabi_epoll_event __user *event)
+{
+       struct oabi_epoll_event user;
+       struct epoll_event kernel;
+       mm_segment_t fs;
+       long ret;
+
+       if (op == EPOLL_CTL_DEL)
+               return sys_epoll_ctl(epfd, op, fd, NULL);
+       if (copy_from_user(&user, event, sizeof(user)))
+               return -EFAULT;
+       kernel.events = user.events;
+       kernel.data   = user.data;
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_epoll_ctl(epfd, op, fd, &kernel);
+       set_fs(fs);
+       return ret;
+}
+
+asmlinkage long sys_oabi_epoll_wait(int epfd,
+                                   struct oabi_epoll_event __user *events,
+                                   int maxevents, int timeout)
+{
+       struct epoll_event *kbuf;
+       mm_segment_t fs;
+       long ret, err, i;
+
+       if (maxevents <= 0 || maxevents > (INT_MAX/sizeof(struct epoll_event)))
+               return -EINVAL;
+       kbuf = kmalloc(sizeof(*kbuf) * maxevents, GFP_KERNEL);
+       if (!kbuf)
+               return -ENOMEM;
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+       ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout);
+       set_fs(fs);
+       err = 0;
+       for (i = 0; i < ret; i++) {
+               __put_user_error(kbuf[i].events, &events->events, err);
+               __put_user_error(kbuf[i].data,   &events->data,   err);
+               events++;
+       }
+       kfree(kbuf);
+       return err ? -EFAULT : ret;
+}
+
+struct oabi_sembuf {
+       unsigned short  sem_num;
+       short           sem_op;
+       short           sem_flg;
+       unsigned short  __pad;
+};
+
+asmlinkage long sys_oabi_semtimedop(int semid,
+                                   struct oabi_sembuf __user *tsops,
+                                   unsigned nsops,
+                                   const struct timespec __user *timeout)
+{
+       struct sembuf *sops;
+       struct timespec local_timeout;
+       long err;
+       int i;
+
+       if (nsops < 1)
+               return -EINVAL;
+       sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL);
+       if (!sops)
+               return -ENOMEM;
+       err = 0;
+       for (i = 0; i < nsops; i++) {
+               __get_user_error(sops[i].sem_num, &tsops->sem_num, err);
+               __get_user_error(sops[i].sem_op,  &tsops->sem_op,  err);
+               __get_user_error(sops[i].sem_flg, &tsops->sem_flg, err);
+               tsops++;
+       }
+       if (timeout) {
+               /* copy this as well before changing domain protection */
+               err |= copy_from_user(&local_timeout, timeout, sizeof(*timeout));
+               timeout = &local_timeout;
+       }
+       if (err) {
+               err = -EFAULT;
+       } else {
+               mm_segment_t fs = get_fs();
+               set_fs(KERNEL_DS);
+               err = sys_semtimedop(semid, sops, nsops, timeout);
+               set_fs(fs);
+       }
+       kfree(sops);
+       return err;
+}
+
+asmlinkage long sys_oabi_semop(int semid, struct oabi_sembuf __user *tsops,
+                              unsigned nsops)
+{
+       return sys_oabi_semtimedop(semid, tsops, nsops, NULL);
+}
+
+extern asmlinkage int sys_ipc(uint call, int first, int second, int third,
+                             void __user *ptr, long fifth);
+
+asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third,
+                           void __user *ptr, long fifth)
+{
+       switch (call & 0xffff) {
+       case SEMOP:
+               return  sys_oabi_semtimedop(first,
+                                           (struct oabi_sembuf __user *)ptr,
+                                           second, NULL);
+       case SEMTIMEDOP:
+               return  sys_oabi_semtimedop(first,
+                                           (struct oabi_sembuf __user *)ptr,
+                                           second,
+                                           (const struct timespec __user *)fifth);
+       default:
+               return sys_ipc(call, first, second, third, ptr, fifth);
+       }
+}
index 93cfd3ffcc72b6cbc90ff6c7ff8f808b15e3ea15..10235b01582eb8fa2653d26e077536d4ffab0a75 100644 (file)
@@ -404,7 +404,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
        struct thread_info *thread = current_thread_info();
        siginfo_t info;
 
-       if ((no >> 16) != 0x9f)
+       if ((no >> 16) != (__ARM_NR_BASE>> 16))
                return bad_syscall(no, regs);
 
        switch (no & 0xffff) {
index 561e20717b30ccf1280a50a1f3babc1a8d3670d3..55e57a1c2e6ddb756e2e73ba7098f7f5d6fa74e8 100644 (file)
@@ -37,6 +37,7 @@ Boston, MA 02110-1301, USA.  */
 #endif
 
 ENTRY(__ashldi3)
+ENTRY(__aeabi_llsl)
 
        subs    r3, r2, #32
        rsb     ip, r2, #32
index 86fb2a90c30144779a4b620c1978df8c802ab83a..0b31398f89b2ebf7b61549daa9b3befa10cc35cd 100644 (file)
@@ -37,6 +37,7 @@ Boston, MA 02110-1301, USA.  */
 #endif
 
 ENTRY(__ashrdi3)
+ENTRY(__aeabi_lasr)
 
        subs    r3, r2, #32
        rsb     ip, r2, #32
index 59026029d017d33ef784f4e80ece4593cc0cea0e..4e492f4b3f0e48cf1ca14229fc318627a6edc8c2 100644 (file)
@@ -206,6 +206,7 @@ Boston, MA 02111-1307, USA.  */
 
 
 ENTRY(__udivsi3)
+ENTRY(__aeabi_uidiv)
 
        subs    r2, r1, #1
        moveq   pc, lr
@@ -246,6 +247,7 @@ ENTRY(__umodsi3)
 
 
 ENTRY(__divsi3)
+ENTRY(__aeabi_idiv)
 
        cmp     r1, #0
        eor     ip, r0, r1                      @ save the sign of the result.
@@ -303,12 +305,33 @@ ENTRY(__modsi3)
        rsbmi   r0, r0, #0
        mov     pc, lr
 
+#ifdef CONFIG_AEABI
+
+ENTRY(__aeabi_uidivmod)
+
+       stmfd   sp!, {r0, r1, ip, lr}
+       bl      __aeabi_uidiv
+       ldmfd   sp!, {r1, r2, ip, lr}
+       mul     r3, r0, r2
+       sub     r1, r1, r3
+       mov     pc, lr
+
+ENTRY(__aeabi_idivmod)
+
+       stmfd   sp!, {r0, r1, ip, lr}
+       bl      __aeabi_idiv
+       ldmfd   sp!, {r1, r2, ip, lr}
+       mul     r3, r0, r2
+       sub     r1, r1, r3
+       mov     pc, lr
+
+#endif
 
 Ldiv0:
 
-       str     lr, [sp, #-4]!
+       str     lr, [sp, #-8]!
        bl      __div0
        mov     r0, #0                  @ About as wrong as it could be.
-       ldr     pc, [sp], #4
+       ldr     pc, [sp], #8
 
 
index 46c2ed19ec95e2cee4573c052525af2ca5c46f42..a86dbdd59cc4414bbd2a8abaf1f4eab7c3a58237 100644 (file)
@@ -37,6 +37,7 @@ Boston, MA 02110-1301, USA.  */
 #endif
 
 ENTRY(__lshrdi3)
+ENTRY(__aeabi_llsr)
 
        subs    r3, r2, #32
        rsb     ip, r2, #32
index c7fbdf005319ebda1060f1f891e32c50b88c831f..72d594184b8a942bedc437453365b2bb8e970d3e 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 ENTRY(__muldi3)
+ENTRY(__aeabi_lmul)
 
        mul     xh, yl, xh
        mla     xh, xl, yh, xh
index 112630f93e5dda85abc646377876b7dcfabf1745..d847a62834cb134492b058b85760e032b0b665b1 100644 (file)
@@ -10,6 +10,7 @@
  *  published by the Free Software Foundation.
  */
 
+#include <linux/config.h>
 #include <linux/linkage.h>
 
 #ifdef __ARMEB__
@@ -33,3 +34,16 @@ ENTRY(__ucmpdi2)
        movhi   r0, #2
        mov     pc, lr
 
+#ifdef CONFIG_AEABI
+
+ENTRY(__aeabi_ulcmp)
+
+       cmp     xh, yh
+       cmpeq   xl, yl
+       movlo   r0, #-1
+       moveq   r0, #0
+       movhi   r0, #1
+       mov     pc, lr
+
+#endif
+
index f5ef697022962fe7d95117cc44a43b662d40233c..dc5fa8e5ebefa35121f5cc5aa6d5e65bc1f974a7 100644 (file)
@@ -90,7 +90,6 @@ static void __init aaed2000_map_io(void)
 
 MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
        /* Maintainer: Nicolas Bellido Y Ortega */
-       .phys_ram       = 0xf0000000,
        .phys_io        = PIO_BASE,
        .io_pg_offst    = ((VIO_BASE) >> 18) & 0xfffc,
        .map_io         = aaed2000_map_io,
index 4aec834ee47fa49c8008e09a82225023102c343e..54022e58d50dc263d15b29aa51f181f72b48e821 100644 (file)
@@ -132,7 +132,6 @@ static void __init csb337_board_init(void)
 
 MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
-       .phys_ram       = AT91_SDRAM_BASE,
        .phys_io        = AT91_BASE_SYS,
        .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
index 23e4cc21481a5124765ce4443cebb74b31261179..8195f9d919ea56691aa62a1b2b339cddfbb730c1 100644 (file)
@@ -105,7 +105,6 @@ static void __init csb637_board_init(void)
 
 MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
-       .phys_ram       = AT91_SDRAM_BASE,
        .phys_io        = AT91_BASE_SYS,
        .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
index 8c747a31b95aafc81cdca852971d637f2c59bf1f..8a783368366ed16ccbe15eb0dfcd341d7c3c05a5 100644 (file)
@@ -127,7 +127,6 @@ static void __init dk_board_init(void)
 
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
-       .phys_ram       = AT91_SDRAM_BASE,
        .phys_io        = AT91_BASE_SYS,
        .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
index d140645711beab7e0fdad894234f7b6c96ec72f5..fd0752eba897ea771c5b11279ae1a560a44f4fde 100644 (file)
@@ -120,7 +120,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
-       .phys_ram       = AT91_SDRAM_BASE,
        .phys_io        = AT91_BASE_SYS,
        .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
index 43b9423d1440147e0d70d661142ad0c3e63da2c2..c13ca6c56baa1f00f2e44a38782d8d4c40515205 100644 (file)
@@ -64,7 +64,6 @@ void __init autcpu12_map_io(void)
 
 MACHINE_START(AUTCPU12, "autronix autcpu12")
        /* Maintainer: Thomas Gleixner */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0020000,
index cba7be5a06c34423fa311ceef465267ddc7aa1d7..831df007f6c774f95d6d4a3823c2ae1fab785e13 100644 (file)
@@ -55,7 +55,6 @@ static void __init cdb89712_map_io(void)
 
 MACHINE_START(CDB89712, "Cirrus-CDB89712")
        /* Maintainer: Ray Lehtiniemi */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 35d51a759b592c359e86aa7277a3444bce512279..e2b2c5ac8a8340195bc838f70fccc406a7256004 100644 (file)
@@ -56,7 +56,6 @@ static void __init ceiva_map_io(void)
 
 MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame")
        /* Maintainer: Rob Scott */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index c83f3fd68fcd6ba86f90efa68773c125dc380c4f..09fb57e452130d0766f4fe3eab0219138572ea13 100644 (file)
@@ -38,7 +38,6 @@ fixup_clep7312(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
        /* Maintainer: Nobody */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 255c98b63e15f4310bd48efb4d4a24bf25ec931a..dc81cc68595de96edd2f9e2679d1cd855bace03f 100644 (file)
@@ -52,7 +52,6 @@ fixup_edb7211(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
        /* Maintainer: Jon McClintock */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0020100,   /* 0xc0000000 - 0xc001ffff can be video RAM */
index 3d88da0c287b93e5f9389881ad7637335c4331fc..ff26a85aa4bac24b1442d757b81693e0d627a4a1 100644 (file)
@@ -78,7 +78,6 @@ fortunet_fixup(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(FORTUNET, "ARM-FortuNet")
        /* Maintainer: FortuNet Inc. */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000000,
index a1acb945fb5199305acc14951349038ef5ce1968..9ba45f4d5a7e1c5dab8f59e0db1fa01709c336d1 100644 (file)
@@ -90,7 +90,6 @@ static void __init p720t_map_io(void)
 
 MACHINE_START(P720T, "ARM-Prospector720T")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index d869af0023f8e906da3312cf6576aa8507a41092..5b12cab0e6917b750500ac6ae72796768a8c31ff 100644 (file)
@@ -384,7 +384,6 @@ static void __init clps7500_init(void)
 
 MACHINE_START(CLPS7500, "CL-PS7500")
        /* Maintainer: Philip Blundell */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0x03000000,
        .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .map_io         = clps7500_map_io,
index ed4614983adbea91024a70970305d68cd62154c8..6d620d8268cc1b84846d1cb93d3b94e659185ee8 100644 (file)
@@ -284,7 +284,6 @@ arch_initcall(ebsa110_init);
 
 MACHINE_START(EBSA110, "EBSA110")
        /* Maintainer: Russell King */
-       .phys_ram       = 0x00000000,
        .phys_io        = 0xe0000000,
        .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000400,
index 49b898af0032298792b331195bf02bdbc5336b76..5b64d5c5b967764f8ac52dc1f46e836291b610a8 100644 (file)
@@ -85,7 +85,6 @@ fixup_cats(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(CATS, "Chalice-CATS")
        /* Maintainer: Philip Blundell */
-       .phys_ram       = 0x00000000,
        .phys_io        = DC21285_ARMCSR_BASE,
        .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 548a7908168864c485d0c23547d18b73a9ddfe7a..4545576ad8d9e395aa4d88c175ae5f558e69aab1 100644 (file)
@@ -29,7 +29,6 @@ fixup_coebsa285(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(CO285, "co-EBSA285")
        /* Maintainer: Mark van Doesburg */
-       .phys_ram       = 0x00000000,
        .phys_io        = DC21285_ARMCSR_BASE,
        .io_pg_offst    = ((0x7cf00000) >> 18) & 0xfffc,
        .fixup          = fixup_coebsa285,
index 1c37605268d51d501cef77d1ab65140e9f080d71..b1d3bf20a41e4b1d3251d716bd66280dccee5a72 100644 (file)
@@ -14,7 +14,6 @@
 
 MACHINE_START(EBSA285, "EBSA285")
        /* Maintainer: Russell King */
-       .phys_ram       = 0x00000000,
        .phys_io        = DC21285_ARMCSR_BASE,
        .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 9e563de465b53ccc186f17a955838fc91548c4da..229bf0585e40a8c7d0d35669d51d5c714f251a96 100644 (file)
@@ -649,7 +649,6 @@ fixup_netwinder(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
        /* Maintainer: Russell King/Rebel.com */
-       .phys_ram       = 0x00000000,
        .phys_io        = DC21285_ARMCSR_BASE,
        .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 0146b8bb59da36b3ff7323ae2dda0a797c60705c..c4f843fc099d98c4dd405217e06be5ad6676201b 100644 (file)
@@ -14,7 +14,6 @@
 
 MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
        /* Maintainer: Jamey Hicks / George France */
-       .phys_ram       = 0x00000000,
        .phys_io        = DC21285_ARMCSR_BASE,
        .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index fa59e9e2a5c8cf9f1f4fcef74403d7487aa80e21..193f968edac3a0a16c09a0d1266ef71b92806925 100644 (file)
@@ -31,7 +31,6 @@
 
 MACHINE_START(H7201, "Hynix GMS30C7201")
        /* Maintainer: Robert Schwebel, Pengutronix */
-       .phys_ram       = 0x40000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0001000,
index d75c8221d2a595d8fddfbf790826be7226797b45..36266896979c04920e1cae80dfe829618646bb68 100644 (file)
@@ -72,7 +72,6 @@ static void __init init_eval_h7202(void)
 
 MACHINE_START(H7202, "Hynix HMS30C7202")
        /* Maintainer: Robert Schwebel, Pengutronix */
-       .phys_ram       = 0x40000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
        .boot_params    = 0x40000100,
index c9e0cd8ed0169e58a078c4525eea514e4146623d..dc31e3fd6c5725ed823664018202962d2dec7ad3 100644 (file)
@@ -69,7 +69,6 @@ mx1ads_map_io(void)
 
 MACHINE_START(MX1ADS, "Motorola MX1ADS")
        /* Maintainer: Sascha Hauer, Pengutronix */
-       .phys_ram       = 0x08000000,
        .phys_io        = 0x00200000,
        .io_pg_offst    = ((0xe0200000) >> 18) & 0xfffc,
        .boot_params    = 0x08000100,
index 3afedeb56a6e408e65cf04f901b575309e1678ce..d8d3c2a5a97e22692e7decb9c176edead7ce036b 100644 (file)
@@ -347,7 +347,6 @@ static struct sys_timer ap_timer = {
 
 MACHINE_START(INTEGRATOR, "ARM-Integrator")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_ram       = 0x00000000,
        .phys_io        = 0x16000000,
        .io_pg_offst    = ((0xf1600000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 16cf2482a3e978c78a97f4f760a77f0b9d70cdb8..31820170f3068600a373915227d9f6a090cdf9f1 100644 (file)
@@ -578,7 +578,6 @@ static struct sys_timer cp_timer = {
 
 MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_ram       = 0x00000000,
        .phys_io        = 0x16000000,
        .io_pg_offst    = ((0xf1600000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 5b41e3a724e1d34f35aacd1a94372781a2c4710a..622cdc4212dd6f096ca7880f85d42334f0581da1 100644 (file)
@@ -22,20 +22,6 @@ static int lm_match(struct device *dev, struct device_driver *drv)
        return 1;
 }
 
-static struct bus_type lm_bustype = {
-       .name           = "logicmodule",
-       .match          = lm_match,
-//     .suspend        = lm_suspend,
-//     .resume         = lm_resume,
-};
-
-static int __init lm_init(void)
-{
-       return bus_register(&lm_bustype);
-}
-
-postcore_initcall(lm_init);
-
 static int lm_bus_probe(struct device *dev)
 {
        struct lm_device *lmdev = to_lm_device(dev);
@@ -49,16 +35,30 @@ static int lm_bus_remove(struct device *dev)
        struct lm_device *lmdev = to_lm_device(dev);
        struct lm_driver *lmdrv = to_lm_driver(dev->driver);
 
-       lmdrv->remove(lmdev);
+       if (lmdrv->remove)
+               lmdrv->remove(lmdev);
        return 0;
 }
 
+static struct bus_type lm_bustype = {
+       .name           = "logicmodule",
+       .match          = lm_match,
+       .probe          = lm_bus_probe,
+       .remove         = lm_bus_remove,
+//     .suspend        = lm_bus_suspend,
+//     .resume         = lm_bus_resume,
+};
+
+static int __init lm_init(void)
+{
+       return bus_register(&lm_bustype);
+}
+
+postcore_initcall(lm_init);
+
 int lm_driver_register(struct lm_driver *drv)
 {
        drv->drv.bus = &lm_bustype;
-       drv->drv.probe = lm_bus_probe;
-       drv->drv.remove = lm_bus_remove;
-
        return driver_register(&drv->drv);
 }
 
index 80770233b8d40d7970eee8eaf54ed9df2e715da4..e4f4c52d93d44a4606f4bdb8ba36d91b5355b4f6 100644 (file)
@@ -151,7 +151,6 @@ extern void iop321_init_time(void);
 #if defined(CONFIG_ARCH_IQ80321)
 MACHINE_START(IQ80321, "Intel IQ80321")
        /* Maintainer: Intel Corporation */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IQ80321_UART,
        .io_pg_offst    = ((IQ80321_UART) >> 18) & 0xfffc,
        .map_io         = iq80321_map_io,
@@ -163,7 +162,6 @@ MACHINE_END
 #elif defined(CONFIG_ARCH_IQ31244)
 MACHINE_START(IQ31244, "Intel IQ31244")
        /* Maintainer: Intel Corp. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IQ31244_UART,
        .io_pg_offst    = ((IQ31244_UART) >> 18) & 0xfffc,
        .map_io         = iq31244_map_io,
index e6ea1cba6a17b36dbb141bb0a2458ebc4b51851b..63585485123e50ae208e5ea9426efe0e50780296 100644 (file)
@@ -195,7 +195,6 @@ extern void iq80332_map_io(void);
 #if defined(CONFIG_ARCH_IQ80331)
 MACHINE_START(IQ80331, "Intel IQ80331")
        /* Maintainer: Intel Corp. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = 0xfefff000,
        .io_pg_offst    = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
        .map_io         = iq80331_map_io,
@@ -208,7 +207,6 @@ MACHINE_END
 #elif defined(CONFIG_MACH_IQ80332)
 MACHINE_START(IQ80332, "Intel IQ80332")
        /* Maintainer: Intel Corp. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = 0xfefff000,
        .io_pg_offst    = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
        .map_io         = iq80332_map_io,
index 6851abaf5524f6a4b1273339f3c4fb577f59fa2a..cfd5bef3190bb7a70514a42d957a5995052897a1 100644 (file)
@@ -105,6 +105,16 @@ static struct map_desc ixp2000_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
                .length         = IXP2000_MSF_SIZE,
                .type           = MT_IXP2000_DEVICE,
+       }, {
+               .virtual        = IXP2000_SCRATCH_RING_VIRT_BASE,
+               .pfn            = __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
+               .length         = IXP2000_SCRATCH_RING_SIZE,
+               .type           = MT_IXP2000_DEVICE,
+       }, {
+               .virtual        = IXP2000_SRAM0_VIRT_BASE,
+               .pfn            = __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
+               .length         = IXP2000_SRAM0_SIZE,
+               .type           = MT_IXP2000_DEVICE,
        }, {
                .virtual        = IXP2000_PCI_IO_VIRT_BASE,
                .pfn            = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
index 61f6006241bd9d3ba3548de387cdf531e23e80f3..9e5a13bb39d01f4b173e7f2159e88b55c36356af 100644 (file)
@@ -254,7 +254,6 @@ static void __init enp2611_init_machine(void)
 
 MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_ram       = 0x00000000,
        .phys_io        = IXP2000_UART_PHYS_BASE,
        .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index fd280a93637e89d21ab06d7e7950e7ece0398813..7c782403042a4e523780119c9ab1907c58aa07d0 100644 (file)
@@ -169,7 +169,6 @@ void ixdp2400_init_irq(void)
 
 MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = 0x00000000,
        .phys_io        = IXP2000_UART_PHYS_BASE,
        .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index f9073aa28615e41ad801d5b364ed92e7d00d7b66..076e3f8acc961f8f6d8268539cb2254d5a64b74c 100644 (file)
@@ -285,7 +285,6 @@ void ixdp2800_init_irq(void)
 
 MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = 0x00000000,
        .phys_io        = IXP2000_UART_PHYS_BASE,
        .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index e6a882f35da2bf8a43397716a7ca9a2b65077eed..10f06606d460a0b291a6cc6dfddebdbc0cd8d5ed 100644 (file)
@@ -376,7 +376,6 @@ static void __init ixdp2x01_init_machine(void)
 #ifdef CONFIG_ARCH_IXDP2401
 MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = 0x00000000,
        .phys_io        = IXP2000_UART_PHYS_BASE,
        .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
@@ -390,7 +389,6 @@ MACHINE_END
 #ifdef CONFIG_ARCH_IXDP2801
 MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = 0x00000000,
        .phys_io        = IXP2000_UART_PHYS_BASE,
        .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 679594a73981704a3df75bea6d6e3f396474ab5c..13f8a7ac3ba963686b7f7ffec56827673547415b 100644 (file)
@@ -101,7 +101,6 @@ static void __init coyote_init(void)
 #ifdef CONFIG_ARCH_ADI_COYOTE
 MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
@@ -119,7 +118,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_IXDPG425
 MACHINE_START(IXDPG425, "Intel IXDPG425")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
index 038670489970c2131145337490f64751db9eef8d..654e2eed81fb26d9b839dbcdbaa4c5e7eb6ed624 100644 (file)
@@ -142,7 +142,6 @@ static void __init gtwx5715_init(void)
 
 MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
        /* Maintainer: George Joseph */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_UART2_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
index c2e105c89c9561613e30f006f5e238f886f097e4..da72383ee301e15218a737cf91408b4c78ad3a86 100644 (file)
@@ -121,7 +121,6 @@ static void __init ixdp425_init(void)
 #ifdef CONFIG_ARCH_IXDP425
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
@@ -135,7 +134,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_IXDP465
 MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
@@ -149,7 +147,6 @@ MACHINE_END
 #ifdef CONFIG_ARCH_PRPMC1100
 MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
@@ -169,7 +166,6 @@ MACHINE_END
 #ifdef CONFIG_ARCH_AVILA
 MACHINE_START(AVILA, "Gateworks Avila Network Platform")
        /* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
index 49998a8bd4e8991d6b5ac15d2534ab5d1ea8d972..856d56f3b2ae51a8f4a8db0255b277c5a3d9fc7b 100644 (file)
@@ -124,7 +124,6 @@ static void __init nas100d_init(void)
 
 MACHINE_START(NAS100D, "Iomega NAS 100d")
        /* Maintainer: www.nslu2-linux.org */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
index 289e94cb65c29ad7deb3b63ea1e43aa1c327cf80..da9340a5343419c926b52a195ad3782c76cdcc3b 100644 (file)
@@ -123,7 +123,6 @@ static void __init nslu2_init(void)
 
 MACHINE_START(NSLU2, "Linksys NSLU2")
        /* Maintainer: www.nslu2-linux.org */
-       .phys_ram       = PHYS_OFFSET,
        .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
        .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
index 03ed742ae2be2aac5bf24a900d75ea1c060d2353..ac626436e96f09881cfd25e8c2c6827397a000da 100644 (file)
@@ -91,7 +91,6 @@ static void __init l7200_map_io(void)
 
 MACHINE_START(L7200, "LinkUp Systems L7200")
        /* Maintainer: Steve Hill / Scott McConnell */
-       .phys_ram       = 0xf0000000,
        .phys_io        = 0x80040000,
        .io_pg_offst    = ((0xd0000000) >> 18) & 0xfffc,
        .map_io         = l7200_map_io,
index 19f2fa2244c451c8d203a7f8719164cef49b0ff6..2cccc27c62e4029c3c35de1b027c1a2f69d8f934 100644 (file)
@@ -112,7 +112,6 @@ void __init lh7a40x_init_board_irq (void)
 
 MACHINE_START (KEV7A400, "Sharp KEV7a400")
        /* Maintainer: Marc Singer */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 4eb962fdb3a8554530887966f80d7b71ace4eeb3..12e23277c5ea188bb2d8f76dad34cc504e3feab0 100644 (file)
@@ -317,7 +317,6 @@ lpd7a400_map_io(void)
 
 MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
        /* Maintainer: Marc Singer */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
        .boot_params    = 0xc0000100,
@@ -333,7 +332,6 @@ MACHINE_END
 
 MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
        /* Maintainer: Marc Singer */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 4b292e93fbe23563e2a6d8297cad7a3d68427581..bdc20b51b076a137d94c257b799e36724557b8d8 100644 (file)
@@ -109,7 +109,6 @@ static void __init omap_generic_map_io(void)
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
        /* Maintainer: Tony Lindgren <tony@atomide.com> */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index a07e2c9307fa338896ecca300dc88033a8922885..9533c36a92df2e6cf57e5b24664b1ff10bcd640d 100644 (file)
@@ -199,7 +199,6 @@ static void __init h2_map_io(void)
 
 MACHINE_START(OMAP_H2, "TI-H2")
        /* Maintainer: Imre Deak <imre.deak@nokia.com> */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 668e278433c28701762f28b9531b0ecc489406f8..d665efc1c34423025a050e9c124fa858e4a12246 100644 (file)
@@ -215,7 +215,6 @@ static void __init h3_map_io(void)
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
        /* Maintainer: Texas Instruments, Inc. */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 95f1ff36cdcbc0b3e81ee5a2f7f298bcf35c7d05..652f37c7f9063addf813f4a6d8eb50a2142aeb29 100644 (file)
@@ -303,7 +303,6 @@ static void __init innovator_map_io(void)
 
 MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 0448fa7de8a416a48cd1977f29858be54e67c078..58f783930d45486536d5c08c6b7212175693e2a3 100644 (file)
@@ -149,7 +149,6 @@ postcore_initcall(netstar_late_init);
 
 MACHINE_START(NETSTAR, "NetStar OMAP5910")
        /* Maintainer: Ladislav Michl <michl@2n.cz> */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index e990e1bc16696cea8e0b53e1b48409c72e33fbb5..e5d126e8f2764aa4db2ab733c1e64b187855f64c 100644 (file)
@@ -274,7 +274,6 @@ static void __init osk_map_io(void)
 
 MACHINE_START(OMAP_OSK, "TI-OSK")
        /* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 5c975eb5c34b1fc87ac2d3ae9889a76eb8ea4ab9..67fada207622f826349cbe784c91e727a255c9e5 100644 (file)
@@ -76,7 +76,6 @@ static void __init omap_generic_map_io(void)
 }
 
 MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 92ff5dc073510aa950dd1ff4223443b2a85b0949..88708a0c52a25b0915b60e0828a3f6327e838840 100644 (file)
@@ -199,7 +199,6 @@ static void __init omap_perseus2_map_io(void)
 
 MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
        /* Maintainer: Kevin Hilman <kjh@hilman.org> */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 6f9a6220e78ac587254162fcb92651af2f4bdd42..959b4b847c871c57185ecd1d37d365d6588cb8f6 100644 (file)
@@ -281,7 +281,6 @@ EXPORT_SYMBOL(voiceblue_wdt_ping);
 
 MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
        /* Maintainer: Ladislav Michl <michl@2n.cz> */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index c602e7a3d93e33463699e94cbb9b26c7b7410dbe..b937123e5c65dc7c093a3a296d6bb09a2d599131 100644 (file)
@@ -69,7 +69,6 @@ static void __init omap_generic_map_io(void)
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-       .phys_ram       = 0x80000000,
        .phys_io        = 0x48000000,
        .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
index f2554469a76a79beb7b7b060a7fe09ac2041e5df..c3c35d40378a511ac07b76251001c2d14d07c0b2 100644 (file)
@@ -186,7 +186,6 @@ static void __init omap_h4_map_io(void)
 
 MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-       .phys_ram       = 0x80000000,
        .phys_io        = 0x48000000,
        .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
index 5a7b873f29b3cd853a9975626182dcb38d5463c0..7ffd2de8f2f30f6d0eefd2a9d1c14f32a73aa91c 100644 (file)
@@ -342,7 +342,6 @@ static void __init fixup_corgi(struct machine_desc *desc,
 
 #ifdef CONFIG_MACH_CORGI
 MACHINE_START(CORGI, "SHARP Corgi")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_corgi,
@@ -355,7 +354,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_SHEPHERD
 MACHINE_START(SHEPHERD, "SHARP Shepherd")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_corgi,
@@ -368,7 +366,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_HUSKY
 MACHINE_START(HUSKY, "SHARP Husky")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_corgi,
index 7de159e2ab42e173b90d3a84d8b2e0b894f812fa..347b9dea24c6ea67889d49052c6c003c7c58137c 100644 (file)
@@ -183,7 +183,6 @@ static void __init idp_map_io(void)
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
        /* Maintainer: Vibren Technologies */
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = idp_map_io,
index b464bc88ff93234e853f72649763a0c864e87b9f..3e26d7ce5bb287c4aca023c7d9edbb6cd1ad82c7 100644 (file)
@@ -437,7 +437,6 @@ static void __init lubbock_map_io(void)
 
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
        /* Maintainer: MontaVista Software Inc. */
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = lubbock_map_io,
index 8da9d3efe9a01d4d0bf2c551534de1848262c99d..d5bda60209ecaf4866aed1ba40e0fb8532f94fcc 100644 (file)
@@ -489,7 +489,6 @@ static void __init mainstone_map_io(void)
 
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
        /* Maintainer: MontaVista Software Inc. */
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = mainstone_map_io,
index 663c9500598553604f0f04c3f3b9355b29c2e640..911e6ff5a9bd7066435b7070568256351ce93e34 100644 (file)
@@ -311,7 +311,6 @@ static void __init fixup_poodle(struct machine_desc *desc,
 }
 
 MACHINE_START(POODLE, "SHARP Poodle")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_poodle,
index a9eacc06555f2e775da7f0a859ad671293324a2a..c094d99ebf5607103a40b849a4c14096119303d3 100644 (file)
@@ -497,7 +497,6 @@ static void __init fixup_spitz(struct machine_desc *desc,
 
 #ifdef CONFIG_MACH_SPITZ
 MACHINE_START(SPITZ, "SHARP Spitz")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_spitz,
@@ -510,7 +509,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_BORZOI
 MACHINE_START(BORZOI, "SHARP Borzoi")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_spitz,
@@ -523,7 +521,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_AKITA
 MACHINE_START(AKITA, "SHARP Akita")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_spitz,
index e4f92efc616e58e038b4c649ef911163692b1169..d168286ed47053384dd997562d252c237a6a2a6d 100644 (file)
@@ -295,7 +295,6 @@ static void __init fixup_tosa(struct machine_desc *desc,
 }
 
 MACHINE_START(TOSA, "SHARP Tosa")
-       .phys_ram       = 0xa0000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_tosa,
index 129976866d479af79c6ec80b9eedc25d269e7ac7..17f5f4439fe756a966391732a83a02018ed94bd7 100644 (file)
@@ -3,7 +3,6 @@ menu "RealView platform type"
 
 config MACH_REALVIEW_EB
        bool "Support RealView/EB platform"
-       default n
        select ARM_GIC
        help
          Include support for the ARM(R) RealView Emulation Baseboard platform.
index 112f7592aca972cef48f361365631c447d5a2283..d4a586e38d5b2665c797b9558ff24abdc8937a54 100644 (file)
@@ -166,7 +166,6 @@ static void __init realview_eb_init(void)
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_ram       = 0x00000000,
        .phys_io        = REALVIEW_UART0_BASE,
        .io_pg_offst    = (IO_ADDRESS(REALVIEW_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 5c4ac1c008a63439995ca2dcda55e5122ec5521b..208a2b5dba1b009b4515463812a2b686c287db3e 100644 (file)
@@ -177,7 +177,6 @@ extern struct sys_timer ioc_timer;
 
 MACHINE_START(RISCPC, "Acorn-RiscPC")
        /* Maintainer: Russell King */
-       .phys_ram       = 0x10000000,
        .phys_io        = 0x03000000,
        .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
index 0f81fc0c2f7f5abfd07deb5017f5bc68bc965ca4..3e327b8e46bedd7ca29a4ba6bbe35716449b39b3 100644 (file)
@@ -294,7 +294,6 @@ static void __init anubis_map_io(void)
 
 MACHINE_START(ANUBIS, "Simtec-Anubis")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index 4d962717fdf78e32a1ce31eb9e51bf8e92a8f787..995bb8add33176febe146fb1361b686b804c3cf4 100644 (file)
@@ -527,7 +527,6 @@ static void __init bast_init(void)
 
 MACHINE_START(BAST, "Simtec-BAST")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index 0aa8760598f74bf0d27404005623a938693dc19d..1c316f14ed94db669ae0ff00092bf446904eefac 100644 (file)
@@ -171,7 +171,6 @@ static void __init h1940_init(void)
 
 MACHINE_START(H1940, "IPAQ-H1940")
        /* Maintainer: Ben Dooks <ben@fluff.org> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index 378d640ab00bd0029f3e5cb89831319d43eddbfe..116ac31699664cc3f98eaca5a054393c9aea844b 100644 (file)
@@ -128,7 +128,6 @@ MACHINE_START(N30, "Acer-N30")
        /* Maintainer: Christer Weinigel <christer@weinigel.se>,
                                Ben Dooks <ben-linux@fluff.org>
        */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index 42b0eeff2e0f1da322805b24d0941f75f357fa33..07d09509a626cada03ca104f159d8a7e717cd0c1 100644 (file)
@@ -148,7 +148,6 @@ static void __init nexcoder_map_io(void)
 
 MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
        /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index a2eb9ed48fcdc1e53541a1134c6dd703d3d4361d..b39daedf93ca4dd5088921994e08b6597258c40e 100644 (file)
@@ -116,7 +116,6 @@ static void __init otom11_map_io(void)
 
 MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
        /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index f8d86d1e16b667456cec0cd2c7967496c3a08416..0260ed5ab946c1a2c36576f1668c0070642a92a2 100644 (file)
@@ -205,7 +205,6 @@ static void __init rx3715_init_machine(void)
 
 MACHINE_START(RX3715, "IPAQ-RX3715")
        /* Maintainer: Ben Dooks <ben@fluff.org> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index 2c91965ee1c89292e104703c6111029234449d2d..1e76e1fdfcea954bc1211b200a075857fd013f06 100644 (file)
@@ -115,7 +115,6 @@ static void __init smdk2410_init_irq(void)
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
                                    * to SMDK2410 */
        /* Maintainer: Jonas Dietsche */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index 4e31118533e692af460338470185cf0576d11aad..f4315721c3b8b3c2bb0b7d2bf09b6dcc234cd8f9 100644 (file)
@@ -216,7 +216,6 @@ static void __init smdk2440_machine_init(void)
 
 MACHINE_START(S3C2440, "SMDK2440")
        /* Maintainer: Ben Dooks <ben@fluff.org> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index ae7e099bf6c80521eaf32cd9279881642dbea94d..785fc9cdcf7c6b5d4877ab1c29e746e3bd600086 100644 (file)
@@ -395,7 +395,6 @@ static void __init vr1000_map_io(void)
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_ram       = S3C2410_SDRAM_PA,
        .phys_io        = S3C2410_PA_UART,
        .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
index a66ac61233a2f088e2e666ded4b59afaab03ab52..a599bb0d4ab81b3ea868d180e67922002e0d9fde 100644 (file)
@@ -447,7 +447,6 @@ static void __init assabet_map_io(void)
 
 
 MACHINE_START(ASSABET, "Intel-Assabet")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index edccd5eb06be917b257d0ec38f1e135734be7243..f60b7a66dfa022bc66699a7e26b151cb8c1f1c58 100644 (file)
@@ -297,7 +297,6 @@ static void __init badge4_map_io(void)
 }
 
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 508593722bc741527ffdc276342550ad7c93f860..8269a9ef9afe4adda328d83fbe38ebb2ea55f9ab 100644 (file)
@@ -135,7 +135,6 @@ static void __init cerf_init(void)
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
        /* Maintainer: support@intrinsyc.com */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .map_io         = cerf_map_io,
index 522abc036d3a35521bc9acfe4721c5e2cbd025ed..6888816a1935f3047f96f09980ebfe58447adefa 100644 (file)
@@ -191,7 +191,6 @@ static void __init collie_map_io(void)
 }
 
 MACHINE_START(COLLIE, "Sharp-Collie")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .map_io         = collie_map_io,
index e8352b7f74b04df8b02ca55900979e864a9e1d0e..b04d92271020ef1fd980bbf3b81a15d91ca65b5b 100644 (file)
@@ -392,7 +392,6 @@ static void __init h3100_map_io(void)
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
@@ -510,7 +509,6 @@ static void __init h3600_map_io(void)
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
@@ -897,7 +895,6 @@ static void __init h3800_map_io(void)
 }
 
 MACHINE_START(H3800, "Compaq iPAQ H3800")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index c922e043c4246166e01fca70bc1291fa345a7eb2..046b213efd5b6329a702d3502d7a60d95ebb7c17 100644 (file)
@@ -195,7 +195,6 @@ static void __init hackkit_init(void)
  */
 
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 2f671cc3cb99f793a1a186ccae7eeffebd699883..17f5a43acdb75fcca9dfbfb6807e83a4cb0b712a 100644 (file)
@@ -173,7 +173,6 @@ static void __init jornada720_mach_init(void)
 
 MACHINE_START(JORNADA720, "HP Jornada 720")
        /* Maintainer: Michael Gernoth <michael@gernoth.net> */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 8c9e3dd5294269ce89084f0384055292eda9fe20..07d3a696ae7faebb254cd76ae56d214b6ca35da1 100644 (file)
@@ -60,7 +60,6 @@ static void __init lart_map_io(void)
 }
 
 MACHINE_START(LART, "LART")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 58c18f9e9b7bf2a207d2ff03be48820609683980..0709ebab531c2cc976b05bb244090e96e5a2092f 100644 (file)
@@ -146,7 +146,6 @@ static void __init pleb_map_io(void)
 }
 
 MACHINE_START(PLEB, "PLEB")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .map_io         = pleb_map_io,
index 7482288278d96acf17323a5612aa2791ab771d4c..5aafe0b5699270ad7166ab127239357f0a067f64 100644 (file)
@@ -83,7 +83,6 @@ static void __init shannon_map_io(void)
 }
 
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 439ddc9b06d6f1dda4159ab73579410df6340bab..d2c23b2c34d12f3270982c0fc6bee645a1c32f0b 100644 (file)
@@ -229,7 +229,6 @@ arch_initcall(simpad_init);
 
 MACHINE_START(SIMPAD, "Simpad")
        /* Maintainer: Holger Freyther */
-       .phys_ram       = 0xc0000000,
        .phys_io        = 0x80000000,
        .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
index 2d428b6dbb58a808e3384f643dd1888d7fa06645..877600e212dd6cb36c47513fc9be4a3c381bfeb7 100644 (file)
@@ -111,7 +111,6 @@ static struct sys_timer shark_timer = {
 
 MACHINE_START(SHARK, "Shark")
        /* Maintainer: Alexander Schulz */
-       .phys_ram       = 0x08000000,
        .phys_io        = 0x40000000,
        .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .boot_params    = 0x08003000,
index 8d787f4c78e6e65e2387088b58b1db5e287ccfb7..95096afd527154665468168c5cf3928375cff085 100644 (file)
@@ -9,7 +9,6 @@ config ARCH_VERSATILE_PB
 
 config MACH_VERSATILE_AB
        bool "Support Versatile/AB platform"
-       default n
        help
          Include support for the ARM(R) Versatile/AP platform.
 
index 90023745b23a4f0b73f387ff2946de853b30f34b..9ebbe808b41d94ad2c9960d2a9da434a4589de81 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst307.h>
+#include <asm/hardware/vic.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/flash.h>
 #define VA_VIC_BASE            __io_address(VERSATILE_VIC_BASE)
 #define VA_SIC_BASE            __io_address(VERSATILE_SIC_BASE)
 
-static void vic_mask_irq(unsigned int irq)
-{
-       irq -= IRQ_VIC_START;
-       writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR);
-}
-
-static void vic_unmask_irq(unsigned int irq)
-{
-       irq -= IRQ_VIC_START;
-       writel(1 << irq, VA_VIC_BASE + VIC_IRQ_ENABLE);
-}
-
-static struct irqchip vic_chip = {
-       .ack    = vic_mask_irq,
-       .mask   = vic_mask_irq,
-       .unmask = vic_unmask_irq,
-};
-
 static void sic_mask_irq(unsigned int irq)
 {
        irq -= IRQ_SIC_START;
@@ -127,43 +110,12 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 
 void __init versatile_init_irq(void)
 {
-       unsigned int i, value;
-
-       /* Disable all interrupts initially. */
+       unsigned int i;
 
-       writel(0, VA_VIC_BASE + VIC_INT_SELECT);
-       writel(0, VA_VIC_BASE + VIC_IRQ_ENABLE);
-       writel(~0, VA_VIC_BASE + VIC_IRQ_ENABLE_CLEAR);
-       writel(0, VA_VIC_BASE + VIC_IRQ_STATUS);
-       writel(0, VA_VIC_BASE + VIC_ITCR);
-       writel(~0, VA_VIC_BASE + VIC_IRQ_SOFT_CLEAR);
-
-       /*
-        * Make sure we clear all existing interrupts
-        */
-       writel(0, VA_VIC_BASE + VIC_VECT_ADDR);
-       for (i = 0; i < 19; i++) {
-               value = readl(VA_VIC_BASE + VIC_VECT_ADDR);
-               writel(value, VA_VIC_BASE + VIC_VECT_ADDR);
-       }
-
-       for (i = 0; i < 16; i++) {
-               value = readl(VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4));
-               writel(value | VICVectCntl_Enable | i, VA_VIC_BASE + VIC_VECT_CNTL0 + (i * 4));
-       }
-
-       writel(32, VA_VIC_BASE + VIC_DEF_VECT_ADDR);
-
-       for (i = IRQ_VIC_START; i <= IRQ_VIC_END; i++) {
-               if (i != IRQ_VICSOURCE31) {
-                       set_irq_chip(i, &vic_chip);
-                       set_irq_handler(i, do_level_IRQ);
-                       set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-               }
-       }
+       vic_init(VA_VIC_BASE, ~(1 << 31));
 
        set_irq_handler(IRQ_VICSOURCE31, sic_handle_irq);
-       vic_unmask_irq(IRQ_VICSOURCE31);
+       enable_irq(IRQ_VICSOURCE31);
 
        /* Do second interrupt controller */
        writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR);
@@ -877,7 +829,7 @@ static unsigned long versatile_gettimeoffset(void)
        ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
        do {
                ticks1 = ticks2;
-               status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
+               status = __raw_readl(VA_IC_BASE + VIC_RAW_STATUS);
                ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
        } while (ticks2 > ticks1);
 
index e74c8a2fbb955c793687bce629c25a90cc71ea7a..1eb59678207810a539ee1bdcd01eb706c46ca4a5 100644 (file)
@@ -36,7 +36,6 @@
 
 MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_ram       = 0x00000000,
        .phys_io        = 0x101f1000,
        .io_pg_offst    = ((0xf11f1000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index 22d5ca07f75d60e4f8332f3aaa794542f1aeef05..f17ab4fb548aa5e26f100242828c997dc7b324bc 100644 (file)
@@ -100,7 +100,6 @@ arch_initcall(versatile_pb_init);
 
 MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_ram       = 0x00000000,
        .phys_io        = 0x101f1000,
        .io_pg_offst    = ((0xf11f1000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
index da4c616b6c49886c225a664a4d2b9c31eb052da5..28cd79a451d3abaf2e1471f98833fdea35a8ddfa 100644 (file)
@@ -62,7 +62,7 @@ typedef union tagFPREG {
 #else
        u32 padding[3];
 #endif
-} FPREG;
+} __attribute__ ((packed,aligned(4))) FPREG;
 
 /*
  * FPA11 device model.
@@ -89,7 +89,7 @@ typedef struct tagFPA11 {
                                   so we can use it to detect whether this
                                   instance of the emulator needs to be
                                   initialised. */
-} FPA11;
+} __attribute__ ((packed,aligned(4))) FPA11;
 
 extern int8 SetRoundingMode(const unsigned int);
 extern int8 SetRoundingPrecision(const unsigned int);
index 9693e9b4ffd1e70b024803b251b8a3629b5f41f9..0887bb2a255180e856016eaeee7532d2bed74a6f 100644 (file)
@@ -22,7 +22,6 @@ comment "OMAP Feature Selections"
 config OMAP_RESET_CLOCKS
        bool "Reset unused clocks during boot"
        depends on ARCH_OMAP
-       default n
        help
          Say Y if you want to reset unused clocks during boot.
          This option saves power, but assumes all drivers are
@@ -44,7 +43,6 @@ config OMAP_MUX
 config OMAP_MUX_DEBUG
        bool "Multiplexing debug output"
         depends on OMAP_MUX
-        default n
         help
           Makes the multiplexing functions print out a lot of debug info.
           This is useful if you want to find out the correct values of the
@@ -93,7 +91,6 @@ config OMAP_32K_TIMER_HZ
 
 config OMAP_DM_TIMER
        bool "Use dual-mode timer"
-       default n
        depends on ARCH_OMAP16XX
        help
         Select this option if you want to use OMAP Dual-Mode timers.
index d5d0df7f04fcbcf631d9c22884552f4bedaffaea..cbde675bc95c869d6bd06dc21b36a338a00c61b4 100644 (file)
@@ -702,6 +702,15 @@ config PHYSICAL_START
 
          Don't change this unless you know what you are doing.
 
+config HOTPLUG_CPU
+       bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
+       depends on SMP && HOTPLUG && EXPERIMENTAL
+       ---help---
+         Say Y here to experiment with turning CPUs off and on.  CPUs
+         can be controlled through /sys/devices/system/cpu.
+
+         Say N.
+
 endmenu
 
 
@@ -988,15 +997,6 @@ config SCx200
          This support is also available as a module.  If compiled as a
          module, it will be called scx200.
 
-config HOTPLUG_CPU
-       bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
-       depends on SMP && HOTPLUG && EXPERIMENTAL
-       ---help---
-         Say Y here to experiment with turning CPUs off and on.  CPUs
-         can be controlled through /sys/devices/system/cpu.
-
-         Say N.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
index d3c0409d201cebcd2a258c1ab2bb1983959e5d23..bd2d53a9dd2b393ec7a1f3952f889e211fdd139e 100644 (file)
@@ -42,9 +42,9 @@ include $(srctree)/arch/i386/Makefile.cpu
 cflags-$(CONFIG_REGPARM) += $(shell if [ $(call cc-version) -ge 0300 ] ; then \
                             echo "-mregparm=3"; fi ;)
 
-# Disable unit-at-a-time mode, it makes gcc use a lot more stack
-# due to the lack of sharing of stacklots.
-CFLAGS += $(call cc-option,-fno-unit-at-a-time)
+# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
+# a lot more stack due to the lack of sharing of stacklots:
+CFLAGS                         += $(shell if [ $(call cc-version) -lt 0400 ] ; then echo $(call cc-option,-fno-unit-at-a-time); fi ;)
 
 CFLAGS += $(cflags-y)
 
index b9f0030a2ebbc38494bfaee9ae47656672ac0336..0aaebf3e1cfa321a6b20f6ade450063f3554e0f7 100644 (file)
@@ -112,33 +112,38 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
                p < (void *)tinfo + THREAD_SIZE - 3;
 }
 
+static void print_addr_and_symbol(unsigned long addr, char *log_lvl)
+{
+       printk(log_lvl);
+       printk(" [<%08lx>] ", addr);
+       print_symbol("%s", addr);
+       printk("\n");
+}
+
 static inline unsigned long print_context_stack(struct thread_info *tinfo,
-                               unsigned long *stack, unsigned long ebp)
+                               unsigned long *stack, unsigned long ebp,
+                               char *log_lvl)
 {
        unsigned long addr;
 
 #ifdef CONFIG_FRAME_POINTER
        while (valid_stack_ptr(tinfo, (void *)ebp)) {
                addr = *(unsigned long *)(ebp + 4);
-               printk(KERN_EMERG " [<%08lx>] ", addr);
-               print_symbol("%s", addr);
-               printk("\n");
+               print_addr_and_symbol(addr, log_lvl);
                ebp = *(unsigned long *)ebp;
        }
 #else
        while (valid_stack_ptr(tinfo, stack)) {
                addr = *stack++;
-               if (__kernel_text_address(addr)) {
-                       printk(KERN_EMERG " [<%08lx>]", addr);
-                       print_symbol(" %s", addr);
-                       printk("\n");
-               }
+               if (__kernel_text_address(addr))
+                       print_addr_and_symbol(addr, log_lvl);
        }
 #endif
        return ebp;
 }
 
-void show_trace(struct task_struct *task, unsigned long * stack)
+static void show_trace_log_lvl(struct task_struct *task,
+                              unsigned long *stack, char *log_lvl)
 {
        unsigned long ebp;
 
@@ -157,7 +162,7 @@ void show_trace(struct task_struct *task, unsigned long * stack)
                struct thread_info *context;
                context = (struct thread_info *)
                        ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-               ebp = print_context_stack(context, stack, ebp);
+               ebp = print_context_stack(context, stack, ebp, log_lvl);
                stack = (unsigned long*)context->previous_esp;
                if (!stack)
                        break;
@@ -165,7 +170,13 @@ void show_trace(struct task_struct *task, unsigned long * stack)
        }
 }
 
-void show_stack(struct task_struct *task, unsigned long *esp)
+void show_trace(struct task_struct *task, unsigned long * stack)
+{
+       show_trace_log_lvl(task, stack, "");
+}
+
+static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp,
+                              char *log_lvl)
 {
        unsigned long *stack;
        int i;
@@ -178,16 +189,26 @@ void show_stack(struct task_struct *task, unsigned long *esp)
        }
 
        stack = esp;
-       printk(KERN_EMERG);
+       printk(log_lvl);
        for(i = 0; i < kstack_depth_to_print; i++) {
                if (kstack_end(stack))
                        break;
-               if (i && ((i % 8) == 0))
-                       printk("\n" KERN_EMERG "       ");
+               if (i && ((i % 8) == 0)) {
+                       printk("\n");
+                       printk(log_lvl);
+                       printk("       ");
+               }
                printk("%08lx ", *stack++);
        }
-       printk("\n" KERN_EMERG "Call Trace:\n");
-       show_trace(task, esp);
+       printk("\n");
+       printk(log_lvl);
+       printk("Call Trace:\n");
+       show_trace_log_lvl(task, esp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *esp)
+{
+       show_stack_log_lvl(task, esp, "");
 }
 
 /*
@@ -238,7 +259,7 @@ void show_registers(struct pt_regs *regs)
                u8 __user *eip;
 
                printk("\n" KERN_EMERG "Stack: ");
-               show_stack(NULL, (unsigned long*)esp);
+               show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG);
 
                printk(KERN_EMERG "Code: ");
 
index 65f67070db644ab72f43b8e9699d97517cf396ad..83c3645ccc43b08e085da6ba78f99b3f1f9ac0f4 100644 (file)
@@ -449,3 +449,19 @@ static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032,
                         pci_post_fixup_toshiba_ohci1394);
+
+
+/*
+ * Prevent the BIOS trapping accesses to the Cyrix CS5530A video device
+ * configuration space.
+ */
+static void __devinit pci_early_fixup_cyrix_5530(struct pci_dev *dev)
+{
+       u8 r;
+       /* clear 'F4 Video Configuration Trap' bit */
+       pci_read_config_byte(dev, 0x42, &r);
+       r &= 0xfd;
+       pci_write_config_byte(dev, 0x42, r);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY,
+                       pci_early_fixup_cyrix_5530);
index 80f8663bc6d98c8bd70220bbd1fa0625613de6fe..1d07d8072ec21aebbc5fc2c21318c8bccb98d77f 100644 (file)
@@ -701,6 +701,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_SGI_L1_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_SERIAL_SGI_IOC4=y
+CONFIG_SERIAL_SGI_IOC3=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -1046,6 +1047,7 @@ CONFIG_INFINIBAND_IPOIB=m
 # SN Devices
 #
 CONFIG_SGI_IOC4=y
+CONFIG_SGI_IOC3=y
 
 #
 # File systems
index ff8bb3770c9da0487c91bfa96261ced45d68e43a..3cb503b659e684f2fa45e9a31128730e0b02ee23 100644 (file)
@@ -659,6 +659,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_SGI_L1_CONSOLE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_SERIAL_SGI_IOC4=y
+CONFIG_SERIAL_SGI_IOC3=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -899,6 +900,7 @@ CONFIG_INFINIBAND_SRP=m
 # SN Devices
 #
 CONFIG_SGI_IOC4=y
+CONFIG_SGI_IOC3=y
 
 #
 # File systems
index a346e1833bf2335b224a298469911233dab809fa..626cdc83668b1bc17a2823deefeadae287b86ef1 100644 (file)
@@ -108,7 +108,6 @@ static struct async_struct *IRQ_ports[NR_IRQS];
 static struct console *console;
 
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 extern struct console *console_drivers; /* from kernel/printk.c */
 
@@ -167,15 +166,9 @@ static  void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
                        }
                }
                seen_esc = 0;
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
 
-               *tty->flip.char_buf_ptr = ch;
-
-               *tty->flip.flag_buf_ptr = 0;
-
-               tty->flip.flag_buf_ptr++;
-               tty->flip.char_buf_ptr++;
-               tty->flip.count++;
+               if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
+                       break;
        }
        tty_flip_buffer_push(tty);
 }
index 2ddbac6f49993b4c0026ea6d12803f80b144f620..ce423910ca976553b363ca42ee29f923423c563a 100644 (file)
@@ -903,5 +903,6 @@ fsyscall_table:
        data8 0
        data8 0
        data8 0
+       data8 0                                                 // 1280
 
        .org fsyscall_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
index 2323377e36950ee236a662bcddada08c2f423d45..5cd6226f44f291c2a9a4fd2fa42374148fc65ab9 100644 (file)
@@ -60,3 +60,30 @@ END(jprobe_break)
 GLOBAL_ENTRY(jprobe_inst_return)
        br.call.sptk.many b0=jprobe_break
 END(jprobe_inst_return)
+
+GLOBAL_ENTRY(invalidate_stacked_regs)
+       movl r16=invalidate_restore_cfm
+       ;;
+       mov b6=r16
+       ;;
+       br.ret.sptk.many b6
+       ;;
+invalidate_restore_cfm:
+       mov r16=ar.rsc
+       ;;
+       mov ar.rsc=r0
+       ;;
+       loadrs
+       ;;
+       mov ar.rsc=r16
+       ;;
+       br.cond.sptk.many rp
+END(invalidate_stacked_regs)
+
+GLOBAL_ENTRY(flush_register_stack)
+       // flush dirty regs to backing store (must be first in insn group)
+       flushrs
+       ;;
+       br.ret.sptk.many rp
+END(flush_register_stack)
+
index 346fedf9ea479a361ea7cdca2173b442b2302adb..50ae8c7d453d5075641a191dcfdf5bf0d4087ece 100644 (file)
@@ -766,11 +766,56 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
        return ret;
 }
 
+struct param_bsp_cfm {
+       unsigned long ip;
+       unsigned long *bsp;
+       unsigned long cfm;
+};
+
+static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg)
+{
+       unsigned long ip;
+       struct param_bsp_cfm *lp = arg;
+
+       do {
+               unw_get_ip(info, &ip);
+               if (ip == 0)
+                       break;
+               if (ip == lp->ip) {
+                       unw_get_bsp(info, (unsigned long*)&lp->bsp);
+                       unw_get_cfm(info, (unsigned long*)&lp->cfm);
+                       return;
+               }
+       } while (unw_unwind(info) >= 0);
+       lp->bsp = 0;
+       lp->cfm = 0;
+       return;
+}
+
 int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct jprobe *jp = container_of(p, struct jprobe, kp);
        unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       struct param_bsp_cfm pa;
+       int bytes;
+
+       /*
+        * Callee owns the argument space and could overwrite it, eg
+        * tail call optimization. So to be absolutely safe
+        * we save the argument space before transfering the control
+        * to instrumented jprobe function which runs in
+        * the process context
+        */
+       pa.ip = regs->cr_iip;
+       unw_init_running(ia64_get_bsp_cfm, &pa);
+       bytes = (char *)ia64_rse_skip_regs(pa.bsp, pa.cfm & 0x3f)
+                               - (char *)pa.bsp;
+       memcpy( kcb->jprobes_saved_stacked_regs,
+               pa.bsp,
+               bytes );
+       kcb->bsp = pa.bsp;
+       kcb->cfm = pa.cfm;
 
        /* save architectural state */
        kcb->jprobe_saved_regs = *regs;
@@ -792,8 +837,20 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
 int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 {
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+       int bytes;
 
+       /* restoring architectural state */
        *regs = kcb->jprobe_saved_regs;
+
+       /* restoring the original argument space */
+       flush_register_stack();
+       bytes = (char *)ia64_rse_skip_regs(kcb->bsp, kcb->cfm & 0x3f)
+                               - (char *)kcb->bsp;
+       memcpy( kcb->bsp,
+               kcb->jprobes_saved_stacked_regs,
+               bytes );
+       invalidate_stacked_regs();
+
        preempt_enable_no_resched();
        return 1;
 }
index db32fc1d39356321950de04b0a586df9ac5dff37..403a80a58c13bf9ef89118ae4f4b7063d28df7e0 100644 (file)
@@ -847,7 +847,7 @@ ia64_state_restore:
        ;;
        mov cr.iim=temp3
        mov cr.iha=temp4
-       dep r22=0,r22,62,2      // pal_min_state, physical, uncached
+       dep r22=0,r22,62,1      // pal_min_state, physical, uncached
        mov IA64_KR(CURRENT)=r21
        ld8 r8=[temp1]          // os_status
        ld8 r10=[temp2]         // context
index a87a162a30865198b179142a90bd1ac548642814..9d5a823479a3f2dd8d6aef4e56edee4a1d309743 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Creates entries in /proc/sal for various system features.
  *
- * Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ * Copyright (c) 2003, 2006 Silicon Graphics, Inc.  All rights reserved.
  * Copyright (c) 2003 Hewlett-Packard Co
  *     Bjorn Helgaas <bjorn.helgaas@hp.com>
  *
  *   mca.c may not pass a buffer, a NULL buffer just indicates that a new
  *   record is available in SAL.
  *   Replace some NR_CPUS by cpus_online, for hotplug cpu.
+ *
+ * Jan  5 2006        kaos@sgi.com
+ *   Handle hotplug cpus coming online.
+ *   Handle hotplug cpus going offline while they still have outstanding records.
+ *   Use the cpu_* macros consistently.
+ *   Replace the counting semaphore with a mutex and a test if the cpumask is non-empty.
+ *   Modify the locking to make the test for "work to do" an atomic operation.
  */
 
 #include <linux/capability.h>
+#include <linux/cpu.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <linux/module.h>
@@ -132,8 +140,8 @@ enum salinfo_state {
 };
 
 struct salinfo_data {
-       volatile cpumask_t      cpu_event;      /* which cpus have outstanding events */
-       struct semaphore        sem;            /* count of cpus with outstanding events (bits set in cpu_event) */
+       cpumask_t               cpu_event;      /* which cpus have outstanding events */
+       struct semaphore        mutex;
        u8                      *log_buffer;
        u64                     log_size;
        u8                      *oemdata;       /* decoded oem data */
@@ -174,6 +182,21 @@ struct salinfo_platform_oemdata_parms {
        int ret;
 };
 
+/* Kick the mutex that tells user space that there is work to do.  Instead of
+ * trying to track the state of the mutex across multiple cpus, in user
+ * context, interrupt context, non-maskable interrupt context and hotplug cpu,
+ * it is far easier just to grab the mutex if it is free then release it.
+ *
+ * This routine must be called with data_saved_lock held, to make the down/up
+ * operation atomic.
+ */
+static void
+salinfo_work_to_do(struct salinfo_data *data)
+{
+       down_trylock(&data->mutex);
+       up(&data->mutex);
+}
+
 static void
 salinfo_platform_oemdata_cpu(void *context)
 {
@@ -212,9 +235,9 @@ salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
 
        BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
 
+       if (irqsafe)
+               spin_lock_irqsave(&data_saved_lock, flags);
        if (buffer) {
-               if (irqsafe)
-                       spin_lock_irqsave(&data_saved_lock, flags);
                for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
                        if (!data_saved->buffer)
                                break;
@@ -232,13 +255,11 @@ salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
                        data_saved->size = size;
                        data_saved->buffer = buffer;
                }
-               if (irqsafe)
-                       spin_unlock_irqrestore(&data_saved_lock, flags);
        }
-
-       if (!test_and_set_bit(smp_processor_id(), &data->cpu_event)) {
-               if (irqsafe)
-                       up(&data->sem);
+       cpu_set(smp_processor_id(), data->cpu_event);
+       if (irqsafe) {
+               salinfo_work_to_do(data);
+               spin_unlock_irqrestore(&data_saved_lock, flags);
        }
 }
 
@@ -249,20 +270,17 @@ static struct timer_list salinfo_timer;
 static void
 salinfo_timeout_check(struct salinfo_data *data)
 {
-       int i;
+       unsigned long flags;
        if (!data->open)
                return;
-       for_each_online_cpu(i) {
-               if (test_bit(i, &data->cpu_event)) {
-                       /* double up() is not a problem, user space will see no
-                        * records for the additional "events".
-                        */
-                       up(&data->sem);
-               }
+       if (!cpus_empty(data->cpu_event)) {
+               spin_lock_irqsave(&data_saved_lock, flags);
+               salinfo_work_to_do(data);
+               spin_unlock_irqrestore(&data_saved_lock, flags);
        }
 }
 
-static void 
+static void
 salinfo_timeout (unsigned long arg)
 {
        salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
@@ -290,16 +308,20 @@ salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t
        int i, n, cpu = -1;
 
 retry:
-       if (down_trylock(&data->sem)) {
+       if (cpus_empty(data->cpu_event) && down_trylock(&data->mutex)) {
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
-               if (down_interruptible(&data->sem))
+               if (down_interruptible(&data->mutex))
                        return -EINTR;
        }
 
        n = data->cpu_check;
        for (i = 0; i < NR_CPUS; i++) {
-               if (test_bit(n, &data->cpu_event) && cpu_online(n)) {
+               if (cpu_isset(n, data->cpu_event)) {
+                       if (!cpu_online(n)) {
+                               cpu_clear(n, data->cpu_event);
+                               continue;
+                       }
                        cpu = n;
                        break;
                }
@@ -310,9 +332,6 @@ retry:
        if (cpu == -1)
                goto retry;
 
-       /* events are sticky until the user says "clear" */
-       up(&data->sem);
-
        /* for next read, start checking at next CPU */
        data->cpu_check = cpu;
        if (++data->cpu_check == NR_CPUS)
@@ -381,10 +400,8 @@ salinfo_log_release(struct inode *inode, struct file *file)
 static void
 call_on_cpu(int cpu, void (*fn)(void *), void *arg)
 {
-       cpumask_t save_cpus_allowed, new_cpus_allowed;
-       memcpy(&save_cpus_allowed, &current->cpus_allowed, sizeof(save_cpus_allowed));
-       memset(&new_cpus_allowed, 0, sizeof(new_cpus_allowed));
-       set_bit(cpu, &new_cpus_allowed);
+       cpumask_t save_cpus_allowed = current->cpus_allowed;
+       cpumask_t new_cpus_allowed = cpumask_of_cpu(cpu);
        set_cpus_allowed(current, new_cpus_allowed);
        (*fn)(arg);
        set_cpus_allowed(current, save_cpus_allowed);
@@ -433,10 +450,10 @@ retry:
        if (!data->saved_num)
                call_on_cpu(cpu, salinfo_log_read_cpu, data);
        if (!data->log_size) {
-               data->state = STATE_NO_DATA;
-               clear_bit(cpu, &data->cpu_event);
+               data->state = STATE_NO_DATA;
+               cpu_clear(cpu, data->cpu_event);
        } else {
-               data->state = STATE_LOG_RECORD;
+               data->state = STATE_LOG_RECORD;
        }
 }
 
@@ -473,27 +490,31 @@ static int
 salinfo_log_clear(struct salinfo_data *data, int cpu)
 {
        sal_log_record_header_t *rh;
+       unsigned long flags;
+       spin_lock_irqsave(&data_saved_lock, flags);
        data->state = STATE_NO_DATA;
-       if (!test_bit(cpu, &data->cpu_event))
+       if (!cpu_isset(cpu, data->cpu_event)) {
+               spin_unlock_irqrestore(&data_saved_lock, flags);
                return 0;
-       down(&data->sem);
-       clear_bit(cpu, &data->cpu_event);
+       }
+       cpu_clear(cpu, data->cpu_event);
        if (data->saved_num) {
-               unsigned long flags;
-               spin_lock_irqsave(&data_saved_lock, flags);
-               shift1_data_saved(data, data->saved_num - 1 );
+               shift1_data_saved(data, data->saved_num - 1);
                data->saved_num = 0;
-               spin_unlock_irqrestore(&data_saved_lock, flags);
        }
+       spin_unlock_irqrestore(&data_saved_lock, flags);
        rh = (sal_log_record_header_t *)(data->log_buffer);
        /* Corrected errors have already been cleared from SAL */
        if (rh->severity != sal_log_severity_corrected)
                call_on_cpu(cpu, salinfo_log_clear_cpu, data);
        /* clearing a record may make a new record visible */
        salinfo_log_new_read(cpu, data);
-       if (data->state == STATE_LOG_RECORD &&
-           !test_and_set_bit(cpu,  &data->cpu_event))
-               up(&data->sem);
+       if (data->state == STATE_LOG_RECORD) {
+               spin_lock_irqsave(&data_saved_lock, flags);
+               cpu_set(cpu, data->cpu_event);
+               salinfo_work_to_do(data);
+               spin_unlock_irqrestore(&data_saved_lock, flags);
+       }
        return 0;
 }
 
@@ -550,6 +571,53 @@ static struct file_operations salinfo_data_fops = {
        .write   = salinfo_log_write,
 };
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int __devinit
+salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+       unsigned int i, cpu = (unsigned long)hcpu;
+       unsigned long flags;
+       struct salinfo_data *data;
+       switch (action) {
+       case CPU_ONLINE:
+               spin_lock_irqsave(&data_saved_lock, flags);
+               for (i = 0, data = salinfo_data;
+                    i < ARRAY_SIZE(salinfo_data);
+                    ++i, ++data) {
+                       cpu_set(cpu, data->cpu_event);
+                       salinfo_work_to_do(data);
+               }
+               spin_unlock_irqrestore(&data_saved_lock, flags);
+               break;
+       case CPU_DEAD:
+               spin_lock_irqsave(&data_saved_lock, flags);
+               for (i = 0, data = salinfo_data;
+                    i < ARRAY_SIZE(salinfo_data);
+                    ++i, ++data) {
+                       struct salinfo_data_saved *data_saved;
+                       int j;
+                       for (j = ARRAY_SIZE(data->data_saved) - 1, data_saved = data->data_saved + j;
+                            j >= 0;
+                            --j, --data_saved) {
+                               if (data_saved->buffer && data_saved->cpu == cpu) {
+                                       shift1_data_saved(data, j);
+                               }
+                       }
+                       cpu_clear(cpu, data->cpu_event);
+               }
+               spin_unlock_irqrestore(&data_saved_lock, flags);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block salinfo_cpu_notifier =
+{
+       .notifier_call = salinfo_cpu_callback,
+       .priority = 0,
+};
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init
 salinfo_init(void)
 {
@@ -557,7 +625,7 @@ salinfo_init(void)
        struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */
        struct proc_dir_entry *dir, *entry;
        struct salinfo_data *data;
-       int i, j, online;
+       int i, j;
 
        salinfo_dir = proc_mkdir("sal", NULL);
        if (!salinfo_dir)
@@ -572,7 +640,7 @@ salinfo_init(void)
        for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
                data = salinfo_data + i;
                data->type = i;
-               sema_init(&data->sem, 0);
+               init_MUTEX(&data->mutex);
                dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
                if (!dir)
                        continue;
@@ -592,12 +660,8 @@ salinfo_init(void)
                *sdir++ = entry;
 
                /* we missed any events before now */
-               online = 0;
-               for_each_online_cpu(j) {
-                       set_bit(j, &data->cpu_event);
-                       ++online;
-               }
-               sema_init(&data->sem, online);
+               for_each_online_cpu(j)
+                       cpu_set(j, data->cpu_event);
 
                *sdir++ = dir;
        }
@@ -609,6 +673,10 @@ salinfo_init(void)
        salinfo_timer.function = &salinfo_timeout;
        add_timer(&salinfo_timer);
 
+#ifdef CONFIG_HOTPLUG_CPU
+       register_cpu_notifier(&salinfo_cpu_notifier);
+#endif
+
        return 0;
 }
 
index d3e0ecb56d627c0a0514f9bfdefefd1467df0a59..55391901b0137f17184a7e8203d5087581ecd14e 100644 (file)
@@ -530,12 +530,15 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
                if (fsys_mode(current, &regs)) {
                        extern char __kernel_syscall_via_break[];
                        /*
-                        * Got a trap in fsys-mode: Taken Branch Trap and Single Step trap
-                        * need special handling; Debug trap is not supposed to happen.
+                        * Got a trap in fsys-mode: Taken Branch Trap
+                        * and Single Step trap need special handling;
+                        * Debug trap is ignored (we disable it here
+                        * and re-enable it in the lower-privilege trap).
                         */
                        if (unlikely(vector == 29)) {
-                               die("Got debug trap in fsys-mode---not supposed to happen!",
-                                   &regs, 0);
+                               set_thread_flag(TIF_DB_DISABLED);
+                               ia64_psr(&regs)->db = 0;
+                               ia64_psr(&regs)->lp = 1;
                                return;
                        }
                        /* re-do the system call via break 0x100000: */
@@ -589,10 +592,19 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
              case 34:
                if (isr & 0x2) {
                        /* Lower-Privilege Transfer Trap */
+
+                       /* If we disabled debug traps during an fsyscall,
+                        * re-enable them here.
+                        */
+                       if (test_thread_flag(TIF_DB_DISABLED)) {
+                               clear_thread_flag(TIF_DB_DISABLED);
+                               ia64_psr(&regs)->db = 1;
+                       }
+
                        /*
-                        * Just clear PSR.lp and then return immediately: all the
-                        * interesting work (e.g., signal delivery is done in the kernel
-                        * exit path).
+                        * Just clear PSR.lp and then return immediately:
+                        * all the interesting work (e.g., signal delivery)
+                        * is done in the kernel exit path.
                         */
                        ia64_psr(&regs)->lp = 0;
                        return;
index 41105d45442366940006aac1945c425fa93ec8bf..6a4eec9113e8383efd029253a9a038637d6819d0 100644 (file)
@@ -90,7 +90,7 @@ ia64_global_tlb_purge (struct mm_struct *mm, unsigned long start,
 {
        static DEFINE_SPINLOCK(ptcg_lock);
 
-       if (mm != current->active_mm) {
+       if (mm != current->active_mm || !current->mm) {
                flush_tlb_all();
                return;
        }
index 71c2b271b4c687daabd4e886023fe85dacfeeb94..4d417c301201c4a5364a6776d4d965fd1a397571 100644 (file)
 #define IIO_NUM_ITTES   7
 #define HUB_NUM_BIG_WINDOW      (IIO_NUM_ITTES - 1)
 
-struct sn_flush_device_list {
+/* This struct is shared between the PROM and the kernel.
+ * Changes to this struct will require corresponding changes to the kernel.
+ */
+struct sn_flush_device_common {
        int sfdl_bus;
        int sfdl_slot;
        int sfdl_pin;
-       struct bar_list {
+       struct common_bar_list {
                unsigned long start;
                unsigned long end;
        } sfdl_bar_list[6];
@@ -40,14 +43,19 @@ struct sn_flush_device_list {
        uint32_t sfdl_persistent_busnum;
        uint32_t sfdl_persistent_segment;
        struct pcibus_info *sfdl_pcibus_info;
+};
+
+/* This struct is kernel only and is not used by the PROM */
+struct sn_flush_device_kernel {
        spinlock_t sfdl_flush_lock;
+       struct sn_flush_device_common *common;
 };
 
 /*
- * **widget_p - Used as an array[wid_num][device] of sn_flush_device_list.
+ * **widget_p - Used as an array[wid_num][device] of sn_flush_device_kernel.
  */
 struct sn_flush_nasid_entry  {
-       struct sn_flush_device_list **widget_p; /* Used as a array of wid_num */
+       struct sn_flush_device_kernel **widget_p; // Used as an array of wid_num
        uint64_t iio_itte[8];
 };
 
index fcbc748ae4337e7497eafd8c328ef6a4fe376051..f1ec1370b3e37afc87fe9237763b4adc62054e9e 100644 (file)
@@ -33,7 +33,7 @@ void bte_error_handler(unsigned long);
  * Wait until all BTE related CRBs are completed
  * and then reset the interfaces.
  */
-void shub1_bte_error_handler(unsigned long _nodepda)
+int shub1_bte_error_handler(unsigned long _nodepda)
 {
        struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
        struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
@@ -53,7 +53,7 @@ void shub1_bte_error_handler(unsigned long _nodepda)
            (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) {
                BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda,
                            smp_processor_id()));
-               return;
+               return 1;
        }
 
        /* Determine information about our hub */
@@ -81,7 +81,7 @@ void shub1_bte_error_handler(unsigned long _nodepda)
                mod_timer(recovery_timer, HZ * 5);
                BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
                            smp_processor_id()));
-               return;
+               return 1;
        }
        if (icmr.ii_icmr_fld_s.i_crb_vld != 0) {
 
@@ -99,7 +99,7 @@ void shub1_bte_error_handler(unsigned long _nodepda)
                                BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n",
                                            err_nodepda, smp_processor_id(),
                                            i));
-                               return;
+                               return 1;
                        }
                }
        }
@@ -124,6 +124,42 @@ void shub1_bte_error_handler(unsigned long _nodepda)
        REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval);
 
        del_timer(recovery_timer);
+       return 0;
+}
+
+/*
+ * Wait until all BTE related CRBs are completed
+ * and then reset the interfaces.
+ */
+int shub2_bte_error_handler(unsigned long _nodepda)
+{
+       struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
+       struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer;
+       struct bteinfo_s *bte;
+       nasid_t nasid;
+       u64 status;
+       int i;
+
+       nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
+
+       /*
+        * Verify that all the BTEs are complete
+        */
+       for (i = 0; i < BTES_PER_NODE; i++) {
+               bte = &err_nodepda->bte_if[i];
+               status = BTE_LNSTAT_LOAD(bte);
+               if ((status & IBLS_ERROR) || !(status & IBLS_BUSY))
+                       continue;
+               mod_timer(recovery_timer, HZ * 5);
+               BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda,
+                           smp_processor_id()));
+               return 1;
+       }
+       if (ia64_sn_bte_recovery(nasid))
+               panic("bte_error_handler(): Fatal BTE Error");
+
+       del_timer(recovery_timer);
+       return 0;
 }
 
 /*
@@ -135,7 +171,6 @@ void bte_error_handler(unsigned long _nodepda)
        struct nodepda_s *err_nodepda = (struct nodepda_s *)_nodepda;
        spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock;
        int i;
-       nasid_t nasid;
        unsigned long irq_flags;
        volatile u64 *notify;
        bte_result_t bh_error;
@@ -160,12 +195,15 @@ void bte_error_handler(unsigned long _nodepda)
        }
 
        if (is_shub1()) {
-               shub1_bte_error_handler(_nodepda);
+               if (shub1_bte_error_handler(_nodepda)) {
+                       spin_unlock_irqrestore(recovery_lock, irq_flags);
+                       return;
+               }
        } else {
-               nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode);
-
-               if (ia64_sn_bte_recovery(nasid))
-                       panic("bte_error_handler(): Fatal BTE Error");
+               if (shub2_bte_error_handler(_nodepda)) {
+                       spin_unlock_irqrestore(recovery_lock, irq_flags);
+                       return;
+               }
        }
 
        for (i = 0; i < BTES_PER_NODE; i++) {
index 5c5eb01c50f02b53f97513eda0e1e65e3daa2c00..56ab6bae00ee2184c0faecdde66956879e5d66e9 100644 (file)
@@ -32,13 +32,14 @@ static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep)
        ret_stuff.v0 = 0;
        hubdev_info = (struct hubdev_info *)arg;
        nasid = hubdev_info->hdi_nasid;
-       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
+
+       if (is_shub1()) {
+               SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
                        (u64) nasid, 0, 0, 0, 0, 0, 0);
 
-       if ((int)ret_stuff.v0)
-               panic("hubii_eint_handler(): Fatal TIO Error");
+               if ((int)ret_stuff.v0)
+                       panic("hubii_eint_handler(): Fatal TIO Error");
 
-       if (is_shub1()) {
                if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
                        (void)hubiio_crb_error_handler(hubdev_info);
        } else 
index 318087e35b66c2ad2cef6114469d4e873d5fe6b1..258d9d7aff98f759d0af721756310d76b4063199 100644 (file)
@@ -76,11 +76,12 @@ static struct sn_pcibus_provider sn_pci_default_provider = {
 };
 
 /*
- * Retrieve the DMA Flush List given nasid.  This list is needed 
- * to implement the WAR - Flush DMA data on PIO Reads.
+ * Retrieve the DMA Flush List given nasid, widget, and device.
+ * This list is needed to implement the WAR - Flush DMA data on PIO Reads.
  */
-static inline uint64_t
-sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
+static inline u64
+sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
+                            u64 address)
 {
 
        struct ia64_sal_retval ret_stuff;
@@ -88,17 +89,17 @@ sal_get_widget_dmaflush_list(u64 nasid, u64 widget_num, u64 address)
        ret_stuff.v0 = 0;
 
        SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST,
-                       (u64) nasid, (u64) widget_num, (u64) address, 0, 0, 0,
-                       0);
-       return ret_stuff.v0;
+                       (u64) SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST,
+                       (u64) nasid, (u64) widget_num,
+                       (u64) device_num, (u64) address, 0, 0, 0);
+       return ret_stuff.status;
 
 }
 
 /*
  * Retrieve the hub device info structure for the given nasid.
  */
-static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
+static inline u64 sal_get_hubdev_info(u64 handle, u64 address)
 {
 
        struct ia64_sal_retval ret_stuff;
@@ -114,7 +115,7 @@ static inline uint64_t sal_get_hubdev_info(u64 handle, u64 address)
 /*
  * Retrieve the pci bus information given the bus number.
  */
-static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
+static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
 {
 
        struct ia64_sal_retval ret_stuff;
@@ -130,7 +131,7 @@ static inline uint64_t sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
 /*
  * Retrieve the pci device information given the bus and device|function number.
  */
-static inline uint64_t
+static inline u64
 sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev, 
                        u64 sn_irq_info)
 {
@@ -170,12 +171,12 @@ sn_pcidev_info_get(struct pci_dev *dev)
  */
 static void sn_fixup_ionodes(void)
 {
-
-       struct sn_flush_device_list *sn_flush_device_list;
+       struct sn_flush_device_kernel *sn_flush_device_kernel;
+       struct sn_flush_device_kernel *dev_entry;
        struct hubdev_info *hubdev;
-       uint64_t status;
-       uint64_t nasid;
-       int i, widget;
+       u64 status;
+       u64 nasid;
+       int i, widget, device;
 
        /*
         * Get SGI Specific HUB chipset information.
@@ -186,7 +187,7 @@ static void sn_fixup_ionodes(void)
                nasid = cnodeid_to_nasid(i);
                hubdev->max_segment_number = 0xffffffff;
                hubdev->max_pcibus_number = 0xff;
-               status = sal_get_hubdev_info(nasid, (uint64_t) __pa(hubdev));
+               status = sal_get_hubdev_info(nasid, (u64) __pa(hubdev));
                if (status)
                        continue;
 
@@ -213,38 +214,49 @@ static void sn_fixup_ionodes(void)
 
                hubdev->hdi_flush_nasid_list.widget_p =
                    kmalloc((HUB_WIDGET_ID_MAX + 1) *
-                           sizeof(struct sn_flush_device_list *), GFP_KERNEL);
-
+                           sizeof(struct sn_flush_device_kernel *),
+                           GFP_KERNEL);
                memset(hubdev->hdi_flush_nasid_list.widget_p, 0x0,
                       (HUB_WIDGET_ID_MAX + 1) *
-                      sizeof(struct sn_flush_device_list *));
+                      sizeof(struct sn_flush_device_kernel *));
 
                for (widget = 0; widget <= HUB_WIDGET_ID_MAX; widget++) {
-                       sn_flush_device_list = kmalloc(DEV_PER_WIDGET *
-                                                      sizeof(struct
-                                                             sn_flush_device_list),
-                                                      GFP_KERNEL);
-                       memset(sn_flush_device_list, 0x0,
+                       sn_flush_device_kernel = kmalloc(DEV_PER_WIDGET *
+                                                        sizeof(struct
+                                                       sn_flush_device_kernel),
+                                                       GFP_KERNEL);
+                       if (!sn_flush_device_kernel)
+                               BUG();
+                       memset(sn_flush_device_kernel, 0x0,
                               DEV_PER_WIDGET *
-                              sizeof(struct sn_flush_device_list));
-
-                       status =
-                           sal_get_widget_dmaflush_list(nasid, widget,
-                                                        (uint64_t)
-                                                        __pa
-                                                        (sn_flush_device_list));
-                       if (status) {
-                               kfree(sn_flush_device_list);
-                               continue;
+                              sizeof(struct sn_flush_device_kernel));
+
+                       dev_entry = sn_flush_device_kernel;
+                       for (device = 0; device < DEV_PER_WIDGET;
+                            device++,dev_entry++) {
+                               dev_entry->common = kmalloc(sizeof(struct
+                                                       sn_flush_device_common),
+                                                           GFP_KERNEL);
+                               if (!dev_entry->common)
+                                       BUG();
+                               memset(dev_entry->common, 0x0, sizeof(struct
+                                                      sn_flush_device_common));
+
+                               status = sal_get_device_dmaflush_list(nasid,
+                                                                       widget,
+                                                                       device,
+                                                     (u64)(dev_entry->common));
+                               if (status)
+                                       BUG();
+
+                               spin_lock_init(&dev_entry->sfdl_flush_lock);
                        }
 
-                       spin_lock_init(&sn_flush_device_list->sfdl_flush_lock);
-                       hubdev->hdi_flush_nasid_list.widget_p[widget] =
-                           sn_flush_device_list;
-               }
-
+                       if (sn_flush_device_kernel)
+                               hubdev->hdi_flush_nasid_list.widget_p[widget] =
+                                                      sn_flush_device_kernel;
+               }
        }
-
 }
 
 /*
index 493fb3f38dc37af5a7bc919cea2a98a9e06ed326..6a7939b16a1cc1045803e2ad56c2755ce4082616 100644 (file)
@@ -77,12 +77,6 @@ static void tiocx_bus_release(struct device *dev)
        kfree(to_cx_dev(dev));
 }
 
-struct bus_type tiocx_bus_type = {
-       .name = "tiocx",
-       .match = tiocx_match,
-       .uevent = tiocx_uevent,
-};
-
 /**
  * cx_device_match - Find cx_device in the id table.
  * @ids: id table from driver
@@ -149,6 +143,14 @@ static int cx_driver_remove(struct device *dev)
        return 0;
 }
 
+struct bus_type tiocx_bus_type = {
+       .name = "tiocx",
+       .match = tiocx_match,
+       .uevent = tiocx_uevent,
+       .probe = cx_device_probe,
+       .remove = cx_driver_remove,
+};
+
 /**
  * cx_driver_register - Register the driver.
  * @cx_driver: driver table (cx_drv struct) from driver
@@ -162,8 +164,6 @@ int cx_driver_register(struct cx_drv *cx_driver)
 {
        cx_driver->driver.name = cx_driver->name;
        cx_driver->driver.bus = &tiocx_bus_type;
-       cx_driver->driver.probe = cx_device_probe;
-       cx_driver->driver.remove = cx_driver_remove;
 
        return driver_register(&cx_driver->driver);
 }
diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h
deleted file mode 100644 (file)
index 5483a9f..0000000
+++ /dev/null
@@ -1,1273 +0,0 @@
-/*
- * 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) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
- */
-
-
-/*
- * Cross Partition Communication (XPC) structures and macros.
- */
-
-#ifndef _IA64_SN_KERNEL_XPC_H
-#define _IA64_SN_KERNEL_XPC_H
-
-
-#include <linux/config.h>
-#include <linux/interrupt.h>
-#include <linux/sysctl.h>
-#include <linux/device.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/sn/bte.h>
-#include <asm/sn/clksupport.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/mspec.h>
-#include <asm/sn/shub_mmr.h>
-#include <asm/sn/xp.h>
-
-
-/*
- * XPC Version numbers consist of a major and minor number. XPC can always
- * talk to versions with same major #, and never talk to versions with a
- * different major #.
- */
-#define _XPC_VERSION(_maj, _min)       (((_maj) << 4) | ((_min) & 0xf))
-#define XPC_VERSION_MAJOR(_v)          ((_v) >> 4)
-#define XPC_VERSION_MINOR(_v)          ((_v) & 0xf)
-
-
-/*
- * The next macros define word or bit representations for given
- * C-brick nasid in either the SAL provided bit array representing
- * nasids in the partition/machine or the AMO_t array used for
- * inter-partition initiation communications.
- *
- * For SN2 machines, C-Bricks are alway even numbered NASIDs.  As
- * such, some space will be saved by insisting that nasid information
- * passed from SAL always be packed for C-Bricks and the
- * cross-partition interrupts use the same packing scheme.
- */
-#define XPC_NASID_W_INDEX(_n)  (((_n) / 64) / 2)
-#define XPC_NASID_B_INDEX(_n)  (((_n) / 2) & (64 - 1))
-#define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \
-                                   (1UL << XPC_NASID_B_INDEX(_n)))
-#define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2)
-
-#define XPC_HB_DEFAULT_INTERVAL                5       /* incr HB every x secs */
-#define XPC_HB_CHECK_DEFAULT_INTERVAL  20      /* check HB every x secs */
-
-/* define the process name of HB checker and the CPU it is pinned to */
-#define XPC_HB_CHECK_THREAD_NAME       "xpc_hb"
-#define XPC_HB_CHECK_CPU               0
-
-/* define the process name of the discovery thread */
-#define XPC_DISCOVERY_THREAD_NAME      "xpc_discovery"
-
-
-/*
- * the reserved page
- *
- *   SAL reserves one page of memory per partition for XPC. Though a full page
- *   in length (16384 bytes), its starting address is not page aligned, but it
- *   is cacheline aligned. The reserved page consists of the following:
- *
- *   reserved page header
- *
- *     The first cacheline of the reserved page contains the header
- *     (struct xpc_rsvd_page). Before SAL initialization has completed,
- *     SAL has set up the following fields of the reserved page header:
- *     SAL_signature, SAL_version, partid, and nasids_size. The other
- *     fields are set up by XPC. (xpc_rsvd_page points to the local
- *     partition's reserved page.)
- *
- *   part_nasids mask
- *   mach_nasids mask
- *
- *     SAL also sets up two bitmaps (or masks), one that reflects the actual
- *     nasids in this partition (part_nasids), and the other that reflects
- *     the actual nasids in the entire machine (mach_nasids). We're only
- *     interested in the even numbered nasids (which contain the processors
- *     and/or memory), so we only need half as many bits to represent the
- *     nasids. The part_nasids mask is located starting at the first cacheline
- *     following the reserved page header. The mach_nasids mask follows right
- *     after the part_nasids mask. The size in bytes of each mask is reflected
- *     by the reserved page header field 'nasids_size'. (Local partition's
- *     mask pointers are xpc_part_nasids and xpc_mach_nasids.)
- *
- *   vars
- *   vars part
- *
- *     Immediately following the mach_nasids mask are the XPC variables
- *     required by other partitions. First are those that are generic to all
- *     partitions (vars), followed on the next available cacheline by those
- *     which are partition specific (vars part). These are setup by XPC.
- *     (Local partition's vars pointers are xpc_vars and xpc_vars_part.)
- *
- * Note: Until vars_pa is set, the partition XPC code has not been initialized.
- */
-struct xpc_rsvd_page {
-       u64 SAL_signature;      /* SAL: unique signature */
-       u64 SAL_version;        /* SAL: version */
-       u8 partid;              /* SAL: partition ID */
-       u8 version;
-       u8 pad1[6];             /* align to next u64 in cacheline */
-       volatile u64 vars_pa;
-       struct timespec stamp;  /* time when reserved page was setup by XPC */
-       u64 pad2[9];            /* align to last u64 in cacheline */
-       u64 nasids_size;        /* SAL: size of each nasid mask in bytes */
-};
-
-#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */
-
-#define XPC_SUPPORTS_RP_STAMP(_version) \
-                       (_version >= _XPC_VERSION(1,1))
-
-/*
- * compare stamps - the return value is:
- *
- *     < 0,    if stamp1 < stamp2
- *     = 0,    if stamp1 == stamp2
- *     > 0,    if stamp1 > stamp2
- */
-static inline int
-xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2)
-{
-       int ret;
-
-
-       if ((ret = stamp1->tv_sec - stamp2->tv_sec) == 0) {
-               ret = stamp1->tv_nsec - stamp2->tv_nsec;
-       }
-       return ret;
-}
-
-
-/*
- * Define the structures by which XPC variables can be exported to other
- * partitions. (There are two: struct xpc_vars and struct xpc_vars_part)
- */
-
-/*
- * The following structure describes the partition generic variables
- * needed by other partitions in order to properly initialize.
- *
- * struct xpc_vars version number also applies to struct xpc_vars_part.
- * Changes to either structure and/or related functionality should be
- * reflected by incrementing either the major or minor version numbers
- * of struct xpc_vars.
- */
-struct xpc_vars {
-       u8 version;
-       u64 heartbeat;
-       u64 heartbeating_to_mask;
-       u64 heartbeat_offline;  /* if 0, heartbeat should be changing */
-       int act_nasid;
-       int act_phys_cpuid;
-       u64 vars_part_pa;
-       u64 amos_page_pa;       /* paddr of page of AMOs from MSPEC driver */
-       AMO_t *amos_page;       /* vaddr of page of AMOs from MSPEC driver */
-};
-
-#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */
-
-#define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \
-                       (_version >= _XPC_VERSION(3,1))
-
-
-static inline int
-xpc_hb_allowed(partid_t partid, struct xpc_vars *vars)
-{
-       return ((vars->heartbeating_to_mask & (1UL << partid)) != 0);
-}
-
-static inline void
-xpc_allow_hb(partid_t partid, struct xpc_vars *vars)
-{
-       u64 old_mask, new_mask;
-
-       do {
-               old_mask = vars->heartbeating_to_mask;
-               new_mask = (old_mask | (1UL << partid));
-       } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) !=
-                                                       old_mask);
-}
-
-static inline void
-xpc_disallow_hb(partid_t partid, struct xpc_vars *vars)
-{
-       u64 old_mask, new_mask;
-
-       do {
-               old_mask = vars->heartbeating_to_mask;
-               new_mask = (old_mask & ~(1UL << partid));
-       } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) !=
-                                                       old_mask);
-}
-
-
-/*
- * The AMOs page consists of a number of AMO variables which are divided into
- * four groups, The first two groups are used to identify an IRQ's sender.
- * These two groups consist of 64 and 128 AMO variables respectively. The last
- * two groups, consisting of just one AMO variable each, are used to identify
- * the remote partitions that are currently engaged (from the viewpoint of
- * the XPC running on the remote partition).
- */
-#define XPC_NOTIFY_IRQ_AMOS       0
-#define XPC_ACTIVATE_IRQ_AMOS     (XPC_NOTIFY_IRQ_AMOS + XP_MAX_PARTITIONS)
-#define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS)
-#define XPC_DISENGAGE_REQUEST_AMO  (XPC_ENGAGED_PARTITIONS_AMO + 1)
-
-
-/*
- * The following structure describes the per partition specific variables.
- *
- * An array of these structures, one per partition, will be defined. As a
- * partition becomes active XPC will copy the array entry corresponding to
- * itself from that partition. It is desirable that the size of this
- * structure evenly divide into a cacheline, such that none of the entries
- * in this array crosses a cacheline boundary. As it is now, each entry
- * occupies half a cacheline.
- */
-struct xpc_vars_part {
-       volatile u64 magic;
-
-       u64 openclose_args_pa;  /* physical address of open and close args */
-       u64 GPs_pa;             /* physical address of Get/Put values */
-
-       u64 IPI_amo_pa;         /* physical address of IPI AMO_t structure */
-       int IPI_nasid;          /* nasid of where to send IPIs */
-       int IPI_phys_cpuid;     /* physical CPU ID of where to send IPIs */
-
-       u8 nchannels;           /* #of defined channels supported */
-
-       u8 reserved[23];        /* pad to a full 64 bytes */
-};
-
-/*
- * The vars_part MAGIC numbers play a part in the first contact protocol.
- *
- * MAGIC1 indicates that the per partition specific variables for a remote
- * partition have been initialized by this partition.
- *
- * MAGIC2 indicates that this partition has pulled the remote partititions
- * per partition variables that pertain to this partition.
- */
-#define XPC_VP_MAGIC1  0x0053524156435058L  /* 'XPCVARS\0'L (little endian) */
-#define XPC_VP_MAGIC2  0x0073726176435058L  /* 'XPCvars\0'L (little endian) */
-
-
-/* the reserved page sizes and offsets */
-
-#define XPC_RP_HEADER_SIZE     L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
-#define XPC_RP_VARS_SIZE       L1_CACHE_ALIGN(sizeof(struct xpc_vars))
-
-#define XPC_RP_PART_NASIDS(_rp) (u64 *) ((u8 *) _rp + XPC_RP_HEADER_SIZE)
-#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words)
-#define XPC_RP_VARS(_rp)       ((struct xpc_vars *) XPC_RP_MACH_NASIDS(_rp) + xp_nasid_mask_words)
-#define XPC_RP_VARS_PART(_rp)  (struct xpc_vars_part *) ((u8 *) XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE)
-
-
-/*
- * Functions registered by add_timer() or called by kernel_thread() only
- * allow for a single 64-bit argument. The following macros can be used to
- * pack and unpack two (32-bit, 16-bit or 8-bit) arguments into or out from
- * the passed argument.
- */
-#define XPC_PACK_ARGS(_arg1, _arg2) \
-                       ((((u64) _arg1) & 0xffffffff) | \
-                       ((((u64) _arg2) & 0xffffffff) << 32))
-
-#define XPC_UNPACK_ARG1(_args) (((u64) _args) & 0xffffffff)
-#define XPC_UNPACK_ARG2(_args) ((((u64) _args) >> 32) & 0xffffffff)
-
-
-
-/*
- * Define a Get/Put value pair (pointers) used with a message queue.
- */
-struct xpc_gp {
-       volatile s64 get;       /* Get value */
-       volatile s64 put;       /* Put value */
-};
-
-#define XPC_GP_SIZE \
-               L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS)
-
-
-
-/*
- * Define a structure that contains arguments associated with opening and
- * closing a channel.
- */
-struct xpc_openclose_args {
-       u16 reason;             /* reason why channel is closing */
-       u16 msg_size;           /* sizeof each message entry */
-       u16 remote_nentries;    /* #of message entries in remote msg queue */
-       u16 local_nentries;     /* #of message entries in local msg queue */
-       u64 local_msgqueue_pa;  /* physical address of local message queue */
-};
-
-#define XPC_OPENCLOSE_ARGS_SIZE \
-             L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_NCHANNELS)
-
-
-
-/* struct xpc_msg flags */
-
-#define        XPC_M_DONE              0x01    /* msg has been received/consumed */
-#define        XPC_M_READY             0x02    /* msg is ready to be sent */
-#define        XPC_M_INTERRUPT         0x04    /* send interrupt when msg consumed */
-
-
-#define XPC_MSG_ADDRESS(_payload) \
-               ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET))
-
-
-
-/*
- * Defines notify entry.
- *
- * This is used to notify a message's sender that their message was received
- * and consumed by the intended recipient.
- */
-struct xpc_notify {
-       struct semaphore sema;          /* notify semaphore */
-       volatile u8 type;                       /* type of notification */
-
-       /* the following two fields are only used if type == XPC_N_CALL */
-       xpc_notify_func func;           /* user's notify function */
-       void *key;                      /* pointer to user's key */
-};
-
-/* struct xpc_notify type of notification */
-
-#define        XPC_N_CALL              0x01    /* notify function provided by user */
-
-
-
-/*
- * Define the structure that manages all the stuff required by a channel. In
- * particular, they are used to manage the messages sent across the channel.
- *
- * This structure is private to a partition, and is NOT shared across the
- * partition boundary.
- *
- * There is an array of these structures for each remote partition. It is
- * allocated at the time a partition becomes active. The array contains one
- * of these structures for each potential channel connection to that partition.
- *
- * Each of these structures manages two message queues (circular buffers).
- * They are allocated at the time a channel connection is made. One of
- * these message queues (local_msgqueue) holds the locally created messages
- * that are destined for the remote partition. The other of these message
- * queues (remote_msgqueue) is a locally cached copy of the remote partition's
- * own local_msgqueue.
- *
- * The following is a description of the Get/Put pointers used to manage these
- * two message queues. Consider the local_msgqueue to be on one partition
- * and the remote_msgqueue to be its cached copy on another partition. A
- * description of what each of the lettered areas contains is included.
- *
- *
- *                     local_msgqueue      remote_msgqueue
- *
- *                        |/////////|      |/////////|
- *    w_remote_GP.get --> +---------+      |/////////|
- *                        |    F    |      |/////////|
- *     remote_GP.get  --> +---------+      +---------+ <-- local_GP->get
- *                        |         |      |         |
- *                        |         |      |    E    |
- *                        |         |      |         |
- *                        |         |      +---------+ <-- w_local_GP.get
- *                        |    B    |      |/////////|
- *                        |         |      |////D////|
- *                        |         |      |/////////|
- *                        |         |      +---------+ <-- w_remote_GP.put
- *                        |         |      |////C////|
- *      local_GP->put --> +---------+      +---------+ <-- remote_GP.put
- *                        |         |      |/////////|
- *                        |    A    |      |/////////|
- *                        |         |      |/////////|
- *     w_local_GP.put --> +---------+      |/////////|
- *                        |/////////|      |/////////|
- *
- *
- *         ( remote_GP.[get|put] are cached copies of the remote
- *           partition's local_GP->[get|put], and thus their values can
- *           lag behind their counterparts on the remote partition. )
- *
- *
- *  A - Messages that have been allocated, but have not yet been sent to the
- *     remote partition.
- *
- *  B - Messages that have been sent, but have not yet been acknowledged by the
- *      remote partition as having been received.
- *
- *  C - Area that needs to be prepared for the copying of sent messages, by
- *     the clearing of the message flags of any previously received messages.
- *
- *  D - Area into which sent messages are to be copied from the remote
- *     partition's local_msgqueue and then delivered to their intended
- *     recipients. [ To allow for a multi-message copy, another pointer
- *     (next_msg_to_pull) has been added to keep track of the next message
- *     number needing to be copied (pulled). It chases after w_remote_GP.put.
- *     Any messages lying between w_local_GP.get and next_msg_to_pull have
- *     been copied and are ready to be delivered. ]
- *
- *  E - Messages that have been copied and delivered, but have not yet been
- *     acknowledged by the recipient as having been received.
- *
- *  F - Messages that have been acknowledged, but XPC has not yet notified the
- *     sender that the message was received by its intended recipient.
- *     This is also an area that needs to be prepared for the allocating of
- *     new messages, by the clearing of the message flags of the acknowledged
- *     messages.
- */
-struct xpc_channel {
-       partid_t partid;                /* ID of remote partition connected */
-       spinlock_t lock;                /* lock for updating this structure */
-       u32 flags;                      /* general flags */
-
-       enum xpc_retval reason;         /* reason why channel is disconnect'g */
-       int reason_line;                /* line# disconnect initiated from */
-
-       u16 number;                     /* channel # */
-
-       u16 msg_size;                   /* sizeof each msg entry */
-       u16 local_nentries;             /* #of msg entries in local msg queue */
-       u16 remote_nentries;            /* #of msg entries in remote msg queue*/
-
-       void *local_msgqueue_base;      /* base address of kmalloc'd space */
-       struct xpc_msg *local_msgqueue; /* local message queue */
-       void *remote_msgqueue_base;     /* base address of kmalloc'd space */
-       struct xpc_msg *remote_msgqueue;/* cached copy of remote partition's */
-                                       /* local message queue */
-       u64 remote_msgqueue_pa;         /* phys addr of remote partition's */
-                                       /* local message queue */
-
-       atomic_t references;            /* #of external references to queues */
-
-       atomic_t n_on_msg_allocate_wq;   /* #on msg allocation wait queue */
-       wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */
-
-       u8 delayed_IPI_flags;           /* IPI flags received, but delayed */
-                                       /* action until channel disconnected */
-
-       /* queue of msg senders who want to be notified when msg received */
-
-       atomic_t n_to_notify;           /* #of msg senders to notify */
-       struct xpc_notify *notify_queue;/* notify queue for messages sent */
-
-       xpc_channel_func func;          /* user's channel function */
-       void *key;                      /* pointer to user's key */
-
-       struct semaphore msg_to_pull_sema; /* next msg to pull serialization */
-       struct semaphore wdisconnect_sema; /* wait for channel disconnect */
-
-       struct xpc_openclose_args *local_openclose_args; /* args passed on */
-                                       /* opening or closing of channel */
-
-       /* various flavors of local and remote Get/Put values */
-
-       struct xpc_gp *local_GP;        /* local Get/Put values */
-       struct xpc_gp remote_GP;        /* remote Get/Put values */
-       struct xpc_gp w_local_GP;       /* working local Get/Put values */
-       struct xpc_gp w_remote_GP;      /* working remote Get/Put values */
-       s64 next_msg_to_pull;           /* Put value of next msg to pull */
-
-       /* kthread management related fields */
-
-// >>> rethink having kthreads_assigned_limit and kthreads_idle_limit; perhaps
-// >>> allow the assigned limit be unbounded and let the idle limit be dynamic
-// >>> dependent on activity over the last interval of time
-       atomic_t kthreads_assigned;     /* #of kthreads assigned to channel */
-       u32 kthreads_assigned_limit;    /* limit on #of kthreads assigned */
-       atomic_t kthreads_idle;         /* #of kthreads idle waiting for work */
-       u32 kthreads_idle_limit;        /* limit on #of kthreads idle */
-       atomic_t kthreads_active;       /* #of kthreads actively working */
-       // >>> following field is temporary
-       u32 kthreads_created;           /* total #of kthreads created */
-
-       wait_queue_head_t idle_wq;      /* idle kthread wait queue */
-
-} ____cacheline_aligned;
-
-
-/* struct xpc_channel flags */
-
-#define        XPC_C_WASCONNECTED      0x00000001 /* channel was connected */
-
-#define        XPC_C_ROPENREPLY        0x00000002 /* remote open channel reply */
-#define        XPC_C_OPENREPLY         0x00000004 /* local open channel reply */
-#define        XPC_C_ROPENREQUEST      0x00000008 /* remote open channel request */
-#define        XPC_C_OPENREQUEST       0x00000010 /* local open channel request */
-
-#define        XPC_C_SETUP             0x00000020 /* channel's msgqueues are alloc'd */
-#define        XPC_C_CONNECTCALLOUT    0x00000040 /* channel connected callout made */
-#define        XPC_C_CONNECTED         0x00000080 /* local channel is connected */
-#define        XPC_C_CONNECTING        0x00000100 /* channel is being connected */
-
-#define        XPC_C_RCLOSEREPLY       0x00000200 /* remote close channel reply */
-#define        XPC_C_CLOSEREPLY        0x00000400 /* local close channel reply */
-#define        XPC_C_RCLOSEREQUEST     0x00000800 /* remote close channel request */
-#define        XPC_C_CLOSEREQUEST      0x00001000 /* local close channel request */
-
-#define        XPC_C_DISCONNECTED      0x00002000 /* channel is disconnected */
-#define        XPC_C_DISCONNECTING     0x00004000 /* channel is being disconnected */
-#define        XPC_C_DISCONNECTCALLOUT 0x00008000 /* chan disconnected callout made */
-#define        XPC_C_WDISCONNECT       0x00010000 /* waiting for channel disconnect */
-
-
-
-/*
- * Manages channels on a partition basis. There is one of these structures
- * for each partition (a partition will never utilize the structure that
- * represents itself).
- */
-struct xpc_partition {
-
-       /* XPC HB infrastructure */
-
-       u8 remote_rp_version;           /* version# of partition's rsvd pg */
-       struct timespec remote_rp_stamp;/* time when rsvd pg was initialized */
-       u64 remote_rp_pa;               /* phys addr of partition's rsvd pg */
-       u64 remote_vars_pa;             /* phys addr of partition's vars */
-       u64 remote_vars_part_pa;        /* phys addr of partition's vars part */
-       u64 last_heartbeat;             /* HB at last read */
-       u64 remote_amos_page_pa;        /* phys addr of partition's amos page */
-       int remote_act_nasid;           /* active part's act/deact nasid */
-       int remote_act_phys_cpuid;      /* active part's act/deact phys cpuid */
-       u32 act_IRQ_rcvd;               /* IRQs since activation */
-       spinlock_t act_lock;            /* protect updating of act_state */
-       u8 act_state;                   /* from XPC HB viewpoint */
-       u8 remote_vars_version;         /* version# of partition's vars */
-       enum xpc_retval reason;         /* reason partition is deactivating */
-       int reason_line;                /* line# deactivation initiated from */
-       int reactivate_nasid;           /* nasid in partition to reactivate */
-
-       unsigned long disengage_request_timeout; /* timeout in jiffies */
-       struct timer_list disengage_request_timer;
-
-
-       /* XPC infrastructure referencing and teardown control */
-
-       volatile u8 setup_state;        /* infrastructure setup state */
-       wait_queue_head_t teardown_wq;  /* kthread waiting to teardown infra */
-       atomic_t references;            /* #of references to infrastructure */
-
-
-       /*
-        * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN
-        * XPC SETS UP THE NECESSARY INFRASTRUCTURE TO SUPPORT CROSS PARTITION
-        * COMMUNICATION. ALL OF THE FOLLOWING FIELDS WILL BE CLEARED. (THE
-        * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.)
-        */
-
-
-       u8 nchannels;              /* #of defined channels supported */
-       atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */
-       atomic_t nchannels_engaged;/* #of channels engaged with remote part */
-       struct xpc_channel *channels;/* array of channel structures */
-
-       void *local_GPs_base;     /* base address of kmalloc'd space */
-       struct xpc_gp *local_GPs; /* local Get/Put values */
-       void *remote_GPs_base;    /* base address of kmalloc'd space */
-       struct xpc_gp *remote_GPs;/* copy of remote partition's local Get/Put */
-                                 /* values */
-       u64 remote_GPs_pa;        /* phys address of remote partition's local */
-                                 /* Get/Put values */
-
-
-       /* fields used to pass args when opening or closing a channel */
-
-       void *local_openclose_args_base;  /* base address of kmalloc'd space */
-       struct xpc_openclose_args *local_openclose_args;  /* local's args */
-       void *remote_openclose_args_base; /* base address of kmalloc'd space */
-       struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */
-                                         /* args */
-       u64 remote_openclose_args_pa;     /* phys addr of remote's args */
-
-
-       /* IPI sending, receiving and handling related fields */
-
-       int remote_IPI_nasid;       /* nasid of where to send IPIs */
-       int remote_IPI_phys_cpuid;  /* phys CPU ID of where to send IPIs */
-       AMO_t *remote_IPI_amo_va;   /* address of remote IPI AMO_t structure */
-
-       AMO_t *local_IPI_amo_va;    /* address of IPI AMO_t structure */
-       u64 local_IPI_amo;          /* IPI amo flags yet to be handled */
-       char IPI_owner[8];          /* IPI owner's name */
-       struct timer_list dropped_IPI_timer; /* dropped IPI timer */
-
-       spinlock_t IPI_lock;        /* IPI handler lock */
-
-
-       /* channel manager related fields */
-
-       atomic_t channel_mgr_requests;  /* #of requests to activate chan mgr */
-       wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */
-
-} ____cacheline_aligned;
-
-
-/* struct xpc_partition act_state values (for XPC HB) */
-
-#define        XPC_P_INACTIVE          0x00    /* partition is not active */
-#define XPC_P_ACTIVATION_REQ   0x01    /* created thread to activate */
-#define XPC_P_ACTIVATING       0x02    /* activation thread started */
-#define XPC_P_ACTIVE           0x03    /* xpc_partition_up() was called */
-#define XPC_P_DEACTIVATING     0x04    /* partition deactivation initiated */
-
-
-#define XPC_DEACTIVATE_PARTITION(_p, _reason) \
-                       xpc_deactivate_partition(__LINE__, (_p), (_reason))
-
-
-/* struct xpc_partition setup_state values */
-
-#define XPC_P_UNSET            0x00    /* infrastructure was never setup */
-#define XPC_P_SETUP            0x01    /* infrastructure is setup */
-#define XPC_P_WTEARDOWN                0x02    /* waiting to teardown infrastructure */
-#define XPC_P_TORNDOWN         0x03    /* infrastructure is torndown */
-
-
-
-/*
- * struct xpc_partition IPI_timer #of seconds to wait before checking for
- * dropped IPIs. These occur whenever an IPI amo write doesn't complete until
- * after the IPI was received.
- */
-#define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ)
-
-
-/* number of seconds to wait for other partitions to disengage */
-#define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT        90
-
-/* interval in seconds to print 'waiting disengagement' messages */
-#define XPC_DISENGAGE_PRINTMSG_INTERVAL                10
-
-
-#define XPC_PARTID(_p) ((partid_t) ((_p) - &xpc_partitions[0]))
-
-
-
-/* found in xp_main.c */
-extern struct xpc_registration xpc_registrations[];
-
-
-/* found in xpc_main.c */
-extern struct device *xpc_part;
-extern struct device *xpc_chan;
-extern int xpc_disengage_request_timelimit;
-extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *);
-extern void xpc_dropped_IPI_check(struct xpc_partition *);
-extern void xpc_activate_partition(struct xpc_partition *);
-extern void xpc_activate_kthreads(struct xpc_channel *, int);
-extern void xpc_create_kthreads(struct xpc_channel *, int);
-extern void xpc_disconnect_wait(int);
-
-
-/* found in xpc_partition.c */
-extern int xpc_exiting;
-extern struct xpc_vars *xpc_vars;
-extern struct xpc_rsvd_page *xpc_rsvd_page;
-extern struct xpc_vars_part *xpc_vars_part;
-extern struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1];
-extern char xpc_remote_copy_buffer[];
-extern struct xpc_rsvd_page *xpc_rsvd_page_init(void);
-extern void xpc_allow_IPI_ops(void);
-extern void xpc_restrict_IPI_ops(void);
-extern int xpc_identify_act_IRQ_sender(void);
-extern int xpc_partition_disengaged(struct xpc_partition *);
-extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *);
-extern void xpc_mark_partition_inactive(struct xpc_partition *);
-extern void xpc_discovery(void);
-extern void xpc_check_remote_hb(void);
-extern void xpc_deactivate_partition(const int, struct xpc_partition *,
-                                               enum xpc_retval);
-extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *);
-
-
-/* found in xpc_channel.c */
-extern void xpc_initiate_connect(int);
-extern void xpc_initiate_disconnect(int);
-extern enum xpc_retval xpc_initiate_allocate(partid_t, int, u32, void **);
-extern enum xpc_retval xpc_initiate_send(partid_t, int, void *);
-extern enum xpc_retval xpc_initiate_send_notify(partid_t, int, void *,
-                                               xpc_notify_func, void *);
-extern void xpc_initiate_received(partid_t, int, void *);
-extern enum xpc_retval xpc_setup_infrastructure(struct xpc_partition *);
-extern enum xpc_retval xpc_pull_remote_vars_part(struct xpc_partition *);
-extern void xpc_process_channel_activity(struct xpc_partition *);
-extern void xpc_connected_callout(struct xpc_channel *);
-extern void xpc_deliver_msg(struct xpc_channel *);
-extern void xpc_disconnect_channel(const int, struct xpc_channel *,
-                                       enum xpc_retval, unsigned long *);
-extern void xpc_disconnecting_callout(struct xpc_channel *);
-extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval);
-extern void xpc_teardown_infrastructure(struct xpc_partition *);
-
-
-
-static inline void
-xpc_wakeup_channel_mgr(struct xpc_partition *part)
-{
-       if (atomic_inc_return(&part->channel_mgr_requests) == 1) {
-               wake_up(&part->channel_mgr_wq);
-       }
-}
-
-
-
-/*
- * These next two inlines are used to keep us from tearing down a channel's
- * msg queues while a thread may be referencing them.
- */
-static inline void
-xpc_msgqueue_ref(struct xpc_channel *ch)
-{
-       atomic_inc(&ch->references);
-}
-
-static inline void
-xpc_msgqueue_deref(struct xpc_channel *ch)
-{
-       s32 refs = atomic_dec_return(&ch->references);
-
-       DBUG_ON(refs < 0);
-       if (refs == 0) {
-               xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]);
-       }
-}
-
-
-
-#define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \
-               xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs)
-
-
-/*
- * These two inlines are used to keep us from tearing down a partition's
- * setup infrastructure while a thread may be referencing it.
- */
-static inline void
-xpc_part_deref(struct xpc_partition *part)
-{
-       s32 refs = atomic_dec_return(&part->references);
-
-
-       DBUG_ON(refs < 0);
-       if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) {
-               wake_up(&part->teardown_wq);
-       }
-}
-
-static inline int
-xpc_part_ref(struct xpc_partition *part)
-{
-       int setup;
-
-
-       atomic_inc(&part->references);
-       setup = (part->setup_state == XPC_P_SETUP);
-       if (!setup) {
-               xpc_part_deref(part);
-       }
-       return setup;
-}
-
-
-
-/*
- * The following macro is to be used for the setting of the reason and
- * reason_line fields in both the struct xpc_channel and struct xpc_partition
- * structures.
- */
-#define XPC_SET_REASON(_p, _reason, _line) \
-       { \
-               (_p)->reason = _reason; \
-               (_p)->reason_line = _line; \
-       }
-
-
-
-/*
- * This next set of inlines are used to keep track of when a partition is
- * potentially engaged in accessing memory belonging to another partition.
- */
-
-static inline void
-xpc_mark_partition_engaged(struct xpc_partition *part)
-{
-       unsigned long irq_flags;
-       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
-                               (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t)));
-
-
-       local_irq_save(irq_flags);
-
-       /* set bit corresponding to our partid in remote partition's AMO */
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR,
-                                               (1UL << sn_partition_id));
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IPIs and AMOs to it until the heartbeat times out.
-        */
-       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                               variable), xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-}
-
-static inline void
-xpc_mark_partition_disengaged(struct xpc_partition *part)
-{
-       unsigned long irq_flags;
-       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
-                               (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t)));
-
-
-       local_irq_save(irq_flags);
-
-       /* clear bit corresponding to our partid in remote partition's AMO */
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
-                                               ~(1UL << sn_partition_id));
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IPIs and AMOs to it until the heartbeat times out.
-        */
-       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                               variable), xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-}
-
-static inline void
-xpc_request_partition_disengage(struct xpc_partition *part)
-{
-       unsigned long irq_flags;
-       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
-                               (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t)));
-
-
-       local_irq_save(irq_flags);
-
-       /* set bit corresponding to our partid in remote partition's AMO */
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR,
-                                               (1UL << sn_partition_id));
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IPIs and AMOs to it until the heartbeat times out.
-        */
-       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                               variable), xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-}
-
-static inline void
-xpc_cancel_partition_disengage_request(struct xpc_partition *part)
-{
-       unsigned long irq_flags;
-       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
-                               (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t)));
-
-
-       local_irq_save(irq_flags);
-
-       /* clear bit corresponding to our partid in remote partition's AMO */
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
-                                               ~(1UL << sn_partition_id));
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IPIs and AMOs to it until the heartbeat times out.
-        */
-       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
-                               variable), xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-}
-
-static inline u64
-xpc_partition_engaged(u64 partid_mask)
-{
-       AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO;
-
-
-       /* return our partition's AMO variable ANDed with partid_mask */
-       return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) &
-                                                               partid_mask);
-}
-
-static inline u64
-xpc_partition_disengage_requested(u64 partid_mask)
-{
-       AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO;
-
-
-       /* return our partition's AMO variable ANDed with partid_mask */
-       return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) &
-                                                               partid_mask);
-}
-
-static inline void
-xpc_clear_partition_engaged(u64 partid_mask)
-{
-       AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO;
-
-
-       /* clear bit(s) based on partid_mask in our partition's AMO */
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
-                                                               ~partid_mask);
-}
-
-static inline void
-xpc_clear_partition_disengage_request(u64 partid_mask)
-{
-       AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO;
-
-
-       /* clear bit(s) based on partid_mask in our partition's AMO */
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
-                                                               ~partid_mask);
-}
-
-
-
-/*
- * The following set of macros and inlines are used for the sending and
- * receiving of IPIs (also known as IRQs). There are two flavors of IPIs,
- * one that is associated with partition activity (SGI_XPC_ACTIVATE) and
- * the other that is associated with channel activity (SGI_XPC_NOTIFY).
- */
-
-static inline u64
-xpc_IPI_receive(AMO_t *amo)
-{
-       return FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_CLEAR);
-}
-
-
-static inline enum xpc_retval
-xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
-{
-       int ret = 0;
-       unsigned long irq_flags;
-
-
-       local_irq_save(irq_flags);
-
-       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, flag);
-       sn_send_IPI_phys(nasid, phys_cpuid, vector, 0);
-
-       /*
-        * We must always use the nofault function regardless of whether we
-        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
-        * didn't, we'd never know that the other partition is down and would
-        * keep sending IPIs and AMOs to it until the heartbeat times out.
-        */
-       ret = xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->variable),
-                               xp_nofault_PIOR_target));
-
-       local_irq_restore(irq_flags);
-
-       return ((ret == 0) ? xpcSuccess : xpcPioReadError);
-}
-
-
-/*
- * IPIs associated with SGI_XPC_ACTIVATE IRQ.
- */
-
-/*
- * Flag the appropriate AMO variable and send an IPI to the specified node.
- */
-static inline void
-xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid,
-                       int to_phys_cpuid)
-{
-       int w_index = XPC_NASID_W_INDEX(from_nasid);
-       int b_index = XPC_NASID_B_INDEX(from_nasid);
-       AMO_t *amos = (AMO_t *) __va(amos_page_pa +
-                               (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t)));
-
-
-       (void) xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid,
-                               to_phys_cpuid, SGI_XPC_ACTIVATE);
-}
-
-static inline void
-xpc_IPI_send_activate(struct xpc_vars *vars)
-{
-       xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0),
-                               vars->act_nasid, vars->act_phys_cpuid);
-}
-
-static inline void
-xpc_IPI_send_activated(struct xpc_partition *part)
-{
-       xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
-                       part->remote_act_nasid, part->remote_act_phys_cpuid);
-}
-
-static inline void
-xpc_IPI_send_reactivate(struct xpc_partition *part)
-{
-       xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid,
-                               xpc_vars->act_nasid, xpc_vars->act_phys_cpuid);
-}
-
-static inline void
-xpc_IPI_send_disengage(struct xpc_partition *part)
-{
-       xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
-                       part->remote_act_nasid, part->remote_act_phys_cpuid);
-}
-
-
-/*
- * IPIs associated with SGI_XPC_NOTIFY IRQ.
- */
-
-/*
- * Send an IPI to the remote partition that is associated with the
- * specified channel.
- */
-#define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \
-               xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f)
-
-static inline void
-xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string,
-                       unsigned long *irq_flags)
-{
-       struct xpc_partition *part = &xpc_partitions[ch->partid];
-       enum xpc_retval ret;
-
-
-       if (likely(part->act_state != XPC_P_DEACTIVATING)) {
-               ret = xpc_IPI_send(part->remote_IPI_amo_va,
-                                       (u64) ipi_flag << (ch->number * 8),
-                                       part->remote_IPI_nasid,
-                                       part->remote_IPI_phys_cpuid,
-                                       SGI_XPC_NOTIFY);
-               dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
-                       ipi_flag_string, ch->partid, ch->number, ret);
-               if (unlikely(ret != xpcSuccess)) {
-                       if (irq_flags != NULL) {
-                               spin_unlock_irqrestore(&ch->lock, *irq_flags);
-                       }
-                       XPC_DEACTIVATE_PARTITION(part, ret);
-                       if (irq_flags != NULL) {
-                               spin_lock_irqsave(&ch->lock, *irq_flags);
-                       }
-               }
-       }
-}
-
-
-/*
- * Make it look like the remote partition, which is associated with the
- * specified channel, sent us an IPI. This faked IPI will be handled
- * by xpc_dropped_IPI_check().
- */
-#define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \
-               xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f)
-
-static inline void
-xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag,
-                               char *ipi_flag_string)
-{
-       struct xpc_partition *part = &xpc_partitions[ch->partid];
-
-
-       FETCHOP_STORE_OP(TO_AMO((u64) &part->local_IPI_amo_va->variable),
-                       FETCHOP_OR, ((u64) ipi_flag << (ch->number * 8)));
-       dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n",
-               ipi_flag_string, ch->partid, ch->number);
-}
-
-
-/*
- * The sending and receiving of IPIs includes the setting of an AMO variable
- * to indicate the reason the IPI was sent. The 64-bit variable is divided
- * up into eight bytes, ordered from right to left. Byte zero pertains to
- * channel 0, byte one to channel 1, and so on. Each byte is described by
- * the following IPI flags.
- */
-
-#define        XPC_IPI_CLOSEREQUEST    0x01
-#define        XPC_IPI_CLOSEREPLY      0x02
-#define        XPC_IPI_OPENREQUEST     0x04
-#define        XPC_IPI_OPENREPLY       0x08
-#define        XPC_IPI_MSGREQUEST      0x10
-
-
-/* given an AMO variable and a channel#, get its associated IPI flags */
-#define XPC_GET_IPI_FLAGS(_amo, _c)    ((u8) (((_amo) >> ((_c) * 8)) & 0xff))
-#define XPC_SET_IPI_FLAGS(_amo, _c, _f)        (_amo) |= ((u64) (_f) << ((_c) * 8))
-
-#define        XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0f)
-#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo)       ((_amo) & 0x1010101010101010)
-
-
-static inline void
-xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       struct xpc_openclose_args *args = ch->local_openclose_args;
-
-
-       args->reason = ch->reason;
-
-       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags);
-}
-
-static inline void
-xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags);
-}
-
-static inline void
-xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       struct xpc_openclose_args *args = ch->local_openclose_args;
-
-
-       args->msg_size = ch->msg_size;
-       args->local_nentries = ch->local_nentries;
-
-       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags);
-}
-
-static inline void
-xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags)
-{
-       struct xpc_openclose_args *args = ch->local_openclose_args;
-
-
-       args->remote_nentries = ch->remote_nentries;
-       args->local_nentries = ch->local_nentries;
-       args->local_msgqueue_pa = __pa(ch->local_msgqueue);
-
-       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags);
-}
-
-static inline void
-xpc_IPI_send_msgrequest(struct xpc_channel *ch)
-{
-       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL);
-}
-
-static inline void
-xpc_IPI_send_local_msgrequest(struct xpc_channel *ch)
-{
-       XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST);
-}
-
-
-/*
- * Memory for XPC's AMO variables is allocated by the MSPEC driver. These
- * pages are located in the lowest granule. The lowest granule uses 4k pages
- * for cached references and an alternate TLB handler to never provide a
- * cacheable mapping for the entire region. This will prevent speculative
- * reading of cached copies of our lines from being issued which will cause
- * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64
- * AMO variables (based on XP_MAX_PARTITIONS) for message notification and an
- * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition
- * activation and 2 AMO variables for partition deactivation.
- */
-static inline AMO_t *
-xpc_IPI_init(int index)
-{
-       AMO_t *amo = xpc_vars->amos_page + index;
-
-
-       (void) xpc_IPI_receive(amo);    /* clear AMO variable */
-       return amo;
-}
-
-
-
-static inline enum xpc_retval
-xpc_map_bte_errors(bte_result_t error)
-{
-       switch (error) {
-       case BTE_SUCCESS:       return xpcSuccess;
-       case BTEFAIL_DIR:       return xpcBteDirectoryError;
-       case BTEFAIL_POISON:    return xpcBtePoisonError;
-       case BTEFAIL_WERR:      return xpcBteWriteError;
-       case BTEFAIL_ACCESS:    return xpcBteAccessError;
-       case BTEFAIL_PWERR:     return xpcBtePWriteError;
-       case BTEFAIL_PRERR:     return xpcBtePReadError;
-       case BTEFAIL_TOUT:      return xpcBteTimeOutError;
-       case BTEFAIL_XTERR:     return xpcBteXtalkError;
-       case BTEFAIL_NOTAVAIL:  return xpcBteNotAvailable;
-       default:                return xpcBteUnmappedError;
-       }
-}
-
-
-
-static inline void *
-xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
-{
-       /* see if kmalloc will give us cachline aligned memory by default */
-       *base = kmalloc(size, flags);
-       if (*base == NULL) {
-               return NULL;
-       }
-       if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) {
-               return *base;
-       }
-       kfree(*base);
-
-       /* nope, we'll have to do it ourselves */
-       *base = kmalloc(size + L1_CACHE_BYTES, flags);
-       if (*base == NULL) {
-               return NULL;
-       }
-       return (void *) L1_CACHE_ALIGN((u64) *base);
-}
-
-
-/*
- * Check to see if there is any channel activity to/from the specified
- * partition.
- */
-static inline void
-xpc_check_for_channel_activity(struct xpc_partition *part)
-{
-       u64 IPI_amo;
-       unsigned long irq_flags;
-
-
-       IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va);
-       if (IPI_amo == 0) {
-               return;
-       }
-
-       spin_lock_irqsave(&part->IPI_lock, irq_flags);
-       part->local_IPI_amo |= IPI_amo;
-       spin_unlock_irqrestore(&part->IPI_lock, irq_flags);
-
-       dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n",
-               XPC_PARTID(part), IPI_amo);
-
-       xpc_wakeup_channel_mgr(part);
-}
-
-
-#endif /* _IA64_SN_KERNEL_XPC_H */
-
index abf4fc2a87bba20e98014172412be96f84c92f91..0c0a6890240996e97b3b5960302219014b616902 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -24,7 +24,7 @@
 #include <linux/slab.h>
 #include <asm/sn/bte.h>
 #include <asm/sn/sn_sal.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /*
@@ -779,6 +779,12 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
 
        /* both sides are disconnected now */
 
+       if (ch->flags & XPC_C_CONNECTCALLOUT) {
+               spin_unlock_irqrestore(&ch->lock, *irq_flags);
+               xpc_disconnect_callout(ch, xpcDisconnected);
+               spin_lock_irqsave(&ch->lock, *irq_flags);
+       }
+
        /* it's now safe to free the channel's message queues */
        xpc_free_msgqueues(ch);
 
@@ -1645,7 +1651,7 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
 
 
 void
-xpc_disconnecting_callout(struct xpc_channel *ch)
+xpc_disconnect_callout(struct xpc_channel *ch, enum xpc_retval reason)
 {
        /*
         * Let the channel's registerer know that the channel is being
@@ -1654,15 +1660,13 @@ xpc_disconnecting_callout(struct xpc_channel *ch)
         */
 
        if (ch->func != NULL) {
-               dev_dbg(xpc_chan, "ch->func() called, reason=xpcDisconnecting,"
-                       " partid=%d, channel=%d\n", ch->partid, ch->number);
+               dev_dbg(xpc_chan, "ch->func() called, reason=%d, partid=%d, "
+                       "channel=%d\n", reason, ch->partid, ch->number);
 
-               ch->func(xpcDisconnecting, ch->partid, ch->number, NULL,
-                                                               ch->key);
+               ch->func(reason, ch->partid, ch->number, NULL, ch->key);
 
-               dev_dbg(xpc_chan, "ch->func() returned, reason="
-                       "xpcDisconnecting, partid=%d, channel=%d\n",
-                       ch->partid, ch->number);
+               dev_dbg(xpc_chan, "ch->func() returned, reason=%d, partid=%d, "
+                       "channel=%d\n", reason, ch->partid, ch->number);
        }
 }
 
index b617236524c690ea2eb95122e26b9ad133d30819..8930586e0eb4203c64b85201b5b2ab7310bd3166 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -59,7 +59,7 @@
 #include <asm/sn/sn_sal.h>
 #include <asm/kdebug.h>
 #include <asm/uaccess.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /* define two XPC debug device structures to be used with dev_dbg() et al */
@@ -82,6 +82,9 @@ struct device *xpc_part = &xpc_part_dbg_subname;
 struct device *xpc_chan = &xpc_chan_dbg_subname;
 
 
+static int xpc_kdebug_ignore;
+
+
 /* systune related variables for /proc/sys directories */
 
 static int xpc_hb_interval = XPC_HB_DEFAULT_INTERVAL;
@@ -162,6 +165,8 @@ static ctl_table xpc_sys_dir[] = {
 };
 static struct ctl_table_header *xpc_sysctl;
 
+/* non-zero if any remote partition disengage request was timed out */
+int xpc_disengage_request_timedout;
 
 /* #of IRQs received */
 static atomic_t xpc_act_IRQ_rcvd;
@@ -773,7 +778,7 @@ xpc_daemonize_kthread(void *args)
                        ch->flags |= XPC_C_DISCONNECTCALLOUT;
                        spin_unlock_irqrestore(&ch->lock, irq_flags);
 
-                       xpc_disconnecting_callout(ch);
+                       xpc_disconnect_callout(ch, xpcDisconnecting);
                } else {
                        spin_unlock_irqrestore(&ch->lock, irq_flags);
                }
@@ -921,9 +926,9 @@ static void
 xpc_do_exit(enum xpc_retval reason)
 {
        partid_t partid;
-       int active_part_count;
+       int active_part_count, printed_waiting_msg = 0;
        struct xpc_partition *part;
-       unsigned long printmsg_time;
+       unsigned long printmsg_time, disengage_request_timeout = 0;
 
 
        /* a 'rmmod XPC' and a 'reboot' cannot both end up here together */
@@ -953,7 +958,8 @@ xpc_do_exit(enum xpc_retval reason)
 
        /* wait for all partitions to become inactive */
 
-       printmsg_time = jiffies;
+       printmsg_time = jiffies + (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
+       xpc_disengage_request_timedout = 0;
 
        do {
                active_part_count = 0;
@@ -969,20 +975,39 @@ xpc_do_exit(enum xpc_retval reason)
                        active_part_count++;
 
                        XPC_DEACTIVATE_PARTITION(part, reason);
-               }
 
-               if (active_part_count == 0) {
-                       break;
+                       if (part->disengage_request_timeout >
+                                               disengage_request_timeout) {
+                               disengage_request_timeout =
+                                               part->disengage_request_timeout;
+                       }
                }
 
-               if (jiffies >= printmsg_time) {
-                       dev_info(xpc_part, "waiting for partitions to "
-                               "deactivate/disengage, active count=%d, remote "
-                               "engaged=0x%lx\n", active_part_count,
-                               xpc_partition_engaged(1UL << partid));
-
-                       printmsg_time = jiffies +
+               if (xpc_partition_engaged(-1UL)) {
+                       if (time_after(jiffies, printmsg_time)) {
+                               dev_info(xpc_part, "waiting for remote "
+                                       "partitions to disengage, timeout in "
+                                       "%ld seconds\n",
+                                       (disengage_request_timeout - jiffies)
+                                                                       / HZ);
+                               printmsg_time = jiffies +
                                        (XPC_DISENGAGE_PRINTMSG_INTERVAL * HZ);
+                               printed_waiting_msg = 1;
+                       }
+
+               } else if (active_part_count > 0) {
+                       if (printed_waiting_msg) {
+                               dev_info(xpc_part, "waiting for local partition"
+                                       " to disengage\n");
+                               printed_waiting_msg = 0;
+                       }
+
+               } else {
+                       if (!xpc_disengage_request_timedout) {
+                               dev_info(xpc_part, "all partitions have "
+                                       "disengaged\n");
+                       }
+                       break;
                }
 
                /* sleep for a 1/3 of a second or so */
@@ -1000,11 +1025,13 @@ xpc_do_exit(enum xpc_retval reason)
        del_timer_sync(&xpc_hb_timer);
        DBUG_ON(xpc_vars->heartbeating_to_mask != 0);
 
-       /* take ourselves off of the reboot_notifier_list */
-       (void) unregister_reboot_notifier(&xpc_reboot_notifier);
+       if (reason == xpcUnloading) {
+               /* take ourselves off of the reboot_notifier_list */
+               (void) unregister_reboot_notifier(&xpc_reboot_notifier);
 
-       /* take ourselves off of the die_notifier list */
-       (void) unregister_die_notifier(&xpc_die_notifier);
+               /* take ourselves off of the die_notifier list */
+               (void) unregister_die_notifier(&xpc_die_notifier);
+       }
 
        /* close down protections for IPI operations */
        xpc_restrict_IPI_ops();
@@ -1020,7 +1047,35 @@ xpc_do_exit(enum xpc_retval reason)
 
 
 /*
- * Called when the system is about to be either restarted or halted.
+ * This function is called when the system is being rebooted.
+ */
+static int
+xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
+{
+       enum xpc_retval reason;
+
+
+       switch (event) {
+       case SYS_RESTART:
+               reason = xpcSystemReboot;
+               break;
+       case SYS_HALT:
+               reason = xpcSystemHalt;
+               break;
+       case SYS_POWER_OFF:
+               reason = xpcSystemPoweroff;
+               break;
+       default:
+               reason = xpcSystemGoingDown;
+       }
+
+       xpc_do_exit(reason);
+       return NOTIFY_DONE;
+}
+
+
+/*
+ * Notify other partitions to disengage from all references to our memory.
  */
 static void
 xpc_die_disengage(void)
@@ -1028,7 +1083,7 @@ xpc_die_disengage(void)
        struct xpc_partition *part;
        partid_t partid;
        unsigned long engaged;
-       long time, print_time, disengage_request_timeout;
+       long time, printmsg_time, disengage_request_timeout;
 
 
        /* keep xpc_hb_checker thread from doing anything (just in case) */
@@ -1055,57 +1110,53 @@ xpc_die_disengage(void)
                }
        }
 
-       print_time = rtc_time();
-       disengage_request_timeout = print_time +
+       time = rtc_time();
+       printmsg_time = time +
+               (XPC_DISENGAGE_PRINTMSG_INTERVAL * sn_rtc_cycles_per_second);
+       disengage_request_timeout = time +
                (xpc_disengage_request_timelimit * sn_rtc_cycles_per_second);
 
        /* wait for all other partitions to disengage from us */
 
-       while ((engaged = xpc_partition_engaged(-1UL)) &&
-                       (time = rtc_time()) < disengage_request_timeout) {
+       while (1) {
+               engaged = xpc_partition_engaged(-1UL);
+               if (!engaged) {
+                       dev_info(xpc_part, "all partitions have disengaged\n");
+                       break;
+               }
 
-               if (time >= print_time) {
+               time = rtc_time();
+               if (time >= disengage_request_timeout) {
+                       for (partid = 1; partid < XP_MAX_PARTITIONS; partid++) {
+                               if (engaged & (1UL << partid)) {
+                                       dev_info(xpc_part, "disengage from "
+                                               "remote partition %d timed "
+                                               "out\n", partid);
+                               }
+                       }
+                       break;
+               }
+
+               if (time >= printmsg_time) {
                        dev_info(xpc_part, "waiting for remote partitions to "
-                               "disengage, engaged=0x%lx\n", engaged);
-                       print_time = time + (XPC_DISENGAGE_PRINTMSG_INTERVAL *
+                               "disengage, timeout in %ld seconds\n",
+                               (disengage_request_timeout - time) /
+                                               sn_rtc_cycles_per_second);
+                       printmsg_time = time +
+                                       (XPC_DISENGAGE_PRINTMSG_INTERVAL *
                                                sn_rtc_cycles_per_second);
                }
        }
-       dev_info(xpc_part, "finished waiting for remote partitions to "
-                               "disengage, engaged=0x%lx\n", engaged);
-}
-
-
-/*
- * This function is called when the system is being rebooted.
- */
-static int
-xpc_system_reboot(struct notifier_block *nb, unsigned long event, void *unused)
-{
-       enum xpc_retval reason;
-
-
-       switch (event) {
-       case SYS_RESTART:
-               reason = xpcSystemReboot;
-               break;
-       case SYS_HALT:
-               reason = xpcSystemHalt;
-               break;
-       case SYS_POWER_OFF:
-               reason = xpcSystemPoweroff;
-               break;
-       default:
-               reason = xpcSystemGoingDown;
-       }
-
-       xpc_do_exit(reason);
-       return NOTIFY_DONE;
 }
 
 
 /*
- * This function is called when the system is being rebooted.
+ * This function is called when the system is being restarted or halted due
+ * to some sort of system failure. If this is the case we need to notify the
+ * other partitions to disengage from all references to our memory.
+ * This function can also be called when our heartbeater could be offlined
+ * for a time. In this case we need to notify other partitions to not worry
+ * about the lack of a heartbeat.
  */
 static int
 xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
@@ -1115,11 +1166,25 @@ xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused)
        case DIE_MACHINE_HALT:
                xpc_die_disengage();
                break;
+
+       case DIE_KDEBUG_ENTER:
+               /* Should lack of heartbeat be ignored by other partitions? */
+               if (!xpc_kdebug_ignore) {
+                       break;
+               }
+               /* fall through */
        case DIE_MCA_MONARCH_ENTER:
        case DIE_INIT_MONARCH_ENTER:
                xpc_vars->heartbeat++;
                xpc_vars->heartbeat_offline = 1;
                break;
+
+       case DIE_KDEBUG_LEAVE:
+               /* Is lack of heartbeat being ignored by other partitions? */
+               if (!xpc_kdebug_ignore) {
+                       break;
+               }
+               /* fall through */
        case DIE_MCA_MONARCH_LEAVE:
        case DIE_INIT_MONARCH_LEAVE:
                xpc_vars->heartbeat++;
@@ -1344,3 +1409,7 @@ module_param(xpc_disengage_request_timelimit, int, 0);
 MODULE_PARM_DESC(xpc_disengage_request_timelimit, "Number of seconds to wait "
                "for disengage request to complete.");
 
+module_param(xpc_kdebug_ignore, int, 0);
+MODULE_PARM_DESC(xpc_kdebug_ignore, "Should lack of heartbeat be ignored by "
+               "other partitions when dropping into kdebug.");
+
index cdd6431853a1b4cc7cfaafa1d30612ed215b104e..88a730e6cfdbc524e9a867f58c6cddb52e57b086 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 2004-2005 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 
@@ -28,7 +28,7 @@
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/nodepda.h>
 #include <asm/sn/addrs.h>
-#include "xpc.h"
+#include <asm/sn/xpc.h>
 
 
 /* XPC is exiting flag */
@@ -771,7 +771,8 @@ xpc_identify_act_IRQ_req(int nasid)
                }
        }
 
-       if (!xpc_partition_disengaged(part)) {
+       if (part->disengage_request_timeout > 0 &&
+                                       !xpc_partition_disengaged(part)) {
                /* still waiting on other side to disengage from us */
                return;
        }
@@ -873,6 +874,9 @@ xpc_partition_disengaged(struct xpc_partition *part)
                         * request in a timely fashion, so assume it's dead.
                         */
 
+                       dev_info(xpc_part, "disengage from remote partition %d "
+                               "timed out\n", partid);
+                       xpc_disengage_request_timedout = 1;
                        xpc_clear_partition_engaged(1UL << partid);
                        disengaged = 1;
                }
index 34093476e9652fc03938edeadeddb4596d439d34..e68332d93171cfd17e317fb7a18ecb1f99f7fc5b 100644 (file)
@@ -218,7 +218,9 @@ void sn_dma_flush(uint64_t addr)
        uint64_t flags;
        uint64_t itte;
        struct hubdev_info *hubinfo;
-       volatile struct sn_flush_device_list *p;
+       volatile struct sn_flush_device_kernel *p;
+       volatile struct sn_flush_device_common *common;
+
        struct sn_flush_nasid_entry *flush_nasid_list;
 
        if (!sn_ioif_inited)
@@ -268,17 +270,17 @@ void sn_dma_flush(uint64_t addr)
        p = &flush_nasid_list->widget_p[wid_num][0];
 
        /* find a matching BAR */
-       for (i = 0; i < DEV_PER_WIDGET; i++) {
+       for (i = 0; i < DEV_PER_WIDGET; i++,p++) {
+               common = p->common;
                for (j = 0; j < PCI_ROM_RESOURCE; j++) {
-                       if (p->sfdl_bar_list[j].start == 0)
+                       if (common->sfdl_bar_list[j].start == 0)
                                break;
-                       if (addr >= p->sfdl_bar_list[j].start
-                           && addr <= p->sfdl_bar_list[j].end)
+                       if (addr >= common->sfdl_bar_list[j].start
+                           && addr <= common->sfdl_bar_list[j].end)
                                break;
                }
-               if (j < PCI_ROM_RESOURCE && p->sfdl_bar_list[j].start != 0)
+               if (j < PCI_ROM_RESOURCE && common->sfdl_bar_list[j].start != 0)
                        break;
-               p++;
        }
 
        /* if no matching BAR, return without doing anything. */
@@ -304,24 +306,24 @@ void sn_dma_flush(uint64_t addr)
                if ((1 << XWIDGET_PART_REV_NUM_REV(revnum)) & PV907516) {
                        return;
                } else {
-                       pcireg_wrb_flush_get(p->sfdl_pcibus_info,
-                                            (p->sfdl_slot - 1));
+                       pcireg_wrb_flush_get(common->sfdl_pcibus_info,
+                                            (common->sfdl_slot - 1));
                }
        } else {
-               spin_lock_irqsave(&((struct sn_flush_device_list *)p)->
-                                 sfdl_flush_lock, flags);
-
-               *p->sfdl_flush_addr = 0;
+               spin_lock_irqsave((spinlock_t *)&p->sfdl_flush_lock,
+                                 flags);
+               *common->sfdl_flush_addr = 0;
 
                /* force an interrupt. */
-               *(volatile uint32_t *)(p->sfdl_force_int_addr) = 1;
+               *(volatile uint32_t *)(common->sfdl_force_int_addr) = 1;
 
                /* wait for the interrupt to come back. */
-               while (*(p->sfdl_flush_addr) != 0x10f)
+               while (*(common->sfdl_flush_addr) != 0x10f)
                        cpu_relax();
 
                /* okay, everything is synched up. */
-               spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock, flags);
+               spin_unlock_irqrestore((spinlock_t *)&p->sfdl_flush_lock,
+                                      flags);
        }
        return;
 }
index 1f500c81002c88869a47935cad3237eaad10bca3..e328e948175d9e3f69795176318864b883b1fe32 100644 (file)
@@ -92,7 +92,8 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
        cnodeid_t near_cnode;
        struct hubdev_info *hubdev_info;
        struct pcibus_info *soft;
-       struct sn_flush_device_list *sn_flush_device_list;
+       struct sn_flush_device_kernel *sn_flush_device_kernel;
+       struct sn_flush_device_common *common;
 
        if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) {
                return NULL;
@@ -137,20 +138,19 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
        hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
 
        if (hubdev_info->hdi_flush_nasid_list.widget_p) {
-               sn_flush_device_list = hubdev_info->hdi_flush_nasid_list.
+               sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list.
                    widget_p[(int)soft->pbi_buscommon.bs_xid];
-               if (sn_flush_device_list) {
+               if (sn_flush_device_kernel) {
                        for (j = 0; j < DEV_PER_WIDGET;
-                            j++, sn_flush_device_list++) {
-                               if (sn_flush_device_list->sfdl_slot == -1)
+                            j++, sn_flush_device_kernel++) {
+                               common = sn_flush_device_kernel->common;
+                               if (common->sfdl_slot == -1)
                                        continue;
-                               if ((sn_flush_device_list->
-                                    sfdl_persistent_segment ==
+                               if ((common->sfdl_persistent_segment ==
                                     soft->pbi_buscommon.bs_persist_segment) &&
-                                    (sn_flush_device_list->
-                                    sfdl_persistent_busnum ==
+                                    (common->sfdl_persistent_busnum ==
                                     soft->pbi_buscommon.bs_persist_busnum))
-                                       sn_flush_device_list->sfdl_pcibus_info =
+                                       common->sfdl_pcibus_info =
                                            soft;
                        }
                }
index 1eaa0d37f677feffe7e2c8fd4f3439f3bbe6ce41..2d804e2d16d11f64d7482f3d78d36a65fbaf6689 100644 (file)
@@ -173,8 +173,6 @@ int register_parisc_driver(struct parisc_driver *driver)
        WARN_ON(driver->drv.probe != NULL);
        WARN_ON(driver->drv.remove != NULL);
 
-       driver->drv.probe = parisc_driver_probe;
-       driver->drv.remove = parisc_driver_remove;
        driver->drv.name = driver->name;
 
        return driver_register(&driver->drv);
@@ -575,6 +573,8 @@ struct bus_type parisc_bus_type = {
        .name = "parisc",
        .match = parisc_generic_match,
        .dev_attrs = parisc_device_attrs,
+       .probe = parisc_driver_probe,
+       .remove = parisc_driver_remove,
 };
 
 /**
index 01feed0e2a15a9bf45f48f701a36f7384f8c9adc..df338c5cc9103c067185ebd26ebf7f36ad426dc9 100644 (file)
@@ -78,17 +78,6 @@ config PPC_UDBG_16550
        bool
        default n
 
-config CRASH_DUMP
-       bool "kernel crash dumps (EXPERIMENTAL)"
-       depends on PPC_MULTIPLATFORM
-       depends on EXPERIMENTAL
-       help
-         Build a kernel suitable for use as a kdump capture kernel.
-         The kernel will be linked at a different address than normal, and
-         so can only be used for Kdump.
-
-         Don't change this unless you know what you are doing.
-
 config GENERIC_TBSYNC
        bool
        default y if PPC32 && SMP
@@ -584,6 +573,16 @@ 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 PPC_MULTIPLATFORM && PPC64 && EXPERIMENTAL
+       help
+         Build a kernel suitable for use as a kdump capture kernel.
+         The kernel will be linked at a different address than normal, and
+         so can only be used for Kdump.
+
+         Don't change this unless you know what you are doing.
+
 config EMBEDDEDBOOT
        bool
        depends on 8xx || 8260
index d3654a264ef7533a8811f9e170fb4f7b4c5499ab..44dd82b791d17075f2ff44ea1ed2eb47c1024759 100644 (file)
@@ -139,17 +139,14 @@ drivers-$(CONFIG_CPM2)            += arch/ppc/8260_io/
 
 drivers-$(CONFIG_OPROFILE)     += arch/powerpc/oprofile/
 
-defaultimage-$(CONFIG_PPC32)   := zImage
+# Default to zImage, override when needed
+defaultimage-y                 := zImage
 defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux
-defaultimage-$(CONFIG_PPC_PSERIES) := zImage
 KBUILD_IMAGE := $(defaultimage-y)
 all: $(KBUILD_IMAGE)
 
 CPPFLAGS_vmlinux.lds   := -Upowerpc
 
-# All the instructions talk about "make bzImage".
-bzImage: zImage
-
 BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage
 
 .PHONY: $(BOOT_TARGETS)
index b53d677f6742d521867e9512be1e86e45041eae4..840ae595a6178e29c6f0089af02d3213a03369b9 100644 (file)
@@ -25,8 +25,9 @@ HOSTCC                := gcc
 BOOTCFLAGS     := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
                   $(shell $(CROSS32CC) -print-file-name=include) -fPIC
 BOOTAFLAGS     := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
-BOOTLFLAGS     := -T $(srctree)/$(src)/zImage.lds
 OBJCOPYFLAGS    := contents,alloc,load,readonly,data
+OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
+OBJCOPY_MIB_ARGS  := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
 
 zlib       := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
 zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h
@@ -35,7 +36,7 @@ zliblinuxheader := zlib.h zconf.h zutil.h
 $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
 #$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
 
-src-boot := string.S prom.c main.c div64.S crt0.S
+src-boot := crt0.S string.S prom.c stdio.c main.c div64.S
 src-boot += $(zlib)
 src-boot := $(addprefix $(obj)/, $(src-boot))
 obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -70,7 +71,7 @@ quiet_cmd_bootas = BOOTAS  $@
       cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
 
 quiet_cmd_bootld = BOOTLD  $@
-      cmd_bootld = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(2)
+      cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
 
 $(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
        $(call if_changed_dep,bootcc)
@@ -87,12 +88,14 @@ obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section)))
 src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
 gz-sec  = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
 
-hostprogs-y            := addnote addRamDisk
-targets                += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
-                          $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
-                          $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
-                          $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
-                          vmlinux.initrd
+hostprogs-y            := addnote addRamDisk hack-coff
+
+targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
+          zImage.coff zImage.initrd.coff miboot.image miboot.initrd.image \
+          $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
+          $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
+          $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
+          vmlinux.initrd dummy.o
 extra-y                        := initrd.o
 
 quiet_cmd_ramdisk = RAMDISK $@
@@ -114,6 +117,14 @@ quiet_cmd_addsection = ADDSEC  $@
 quiet_cmd_addnote = ADDNOTE $@
       cmd_addnote = $(obj)/addnote $@
 
+quiet_cmd_gen-miboot = GEN     $@
+      cmd_gen-miboot = $(OBJCOPY) $(OBJCOPY_MIB_ARGS) \
+                      --add-section=$1=$(word 2, $^) $< $@
+
+quiet_cmd_gencoff = COFF    $@
+      cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
+                   $(obj)/hack-coff $@
+
 $(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
        $(call if_changed,gzip)
 
@@ -127,22 +138,47 @@ $(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
        $(call if_changed_dep,bootcc)
        $(call cmd,addsection)
 
-$(obj)/zImage.vmode: obj-boot += $(call obj-sec, $(required))
+$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
 $(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
-       $(call cmd,bootld,$(obj-boot))
+       $(call cmd,bootld,$(obj-boot),zImage.lds)
 
-$(obj)/zImage.initrd.vmode: obj-boot += $(call obj-sec, $(required) $(initrd))
+$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: obj-boot += $(call obj-sec, $(required) $(initrd))
 $(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
-       $(call cmd,bootld,$(obj-boot))
+       $(call cmd,bootld,$(obj-boot),zImage.lds)
+
+# For 32-bit powermacs, build the COFF and miboot images
+# as well as the ELF images.
+coffimage-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.coff
+coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.initrd.coff
+mibootimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.image
+mibrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32)  := $(obj)/miboot.initrd.image
 
-$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote
+$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y) \
+                       $(mibootimg-y-y)
        @cp -f $< $@
        $(call if_changed,addnote)
 
-$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote
+$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote \
+                       $(coffrdimg-y-y) $(mibrdimg-y-y)
        @cp -f $< $@
        $(call if_changed,addnote)
 
+$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) \
+                       $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+       $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+       $(call cmd,gencoff)
+
+$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
+                          $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
+       $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
+       $(call cmd,gencoff)
+
+$(obj)/miboot.image: $(obj)/dummy.o $(obj)/vmlinux.gz
+       $(call cmd,gen-miboot,image)
+
+$(obj)/miboot.initrd.image: $(obj)/miboot.image $(images)/ramdisk.image.gz
+       $(call cmd,gen-miboot,initrd)
+
 #-----------------------------------------------------------
 # build u-boot images
 #-----------------------------------------------------------
index d2f2ace56cd34df5e1203a85ce5248e763e3133a..e0192c26037b918f1e195d41d2f5ec9176606535 100644 (file)
 #include "ppc_asm.h"
 
        .text
+       /* a procedure descriptor used when booting this as a COFF file */
+_zimage_start_opd:
+       .long   _zimage_start, 0, 0, 0
+
        .globl  _zimage_start
 _zimage_start:
+       /* Work out the offset between the address we were linked at
+          and the address where we're running. */
        bl      1f
-
-1:
-       mflr    r0
+1:     mflr    r0
        lis     r9,1b@ha
        addi    r9,r9,1b@l
        subf.   r0,r9,r0
-       beq     3f
+       beq     3f              /* if running at same address as linked */
 
+       /* The .got2 section contains a list of addresses, so add
+          the address offset onto each entry. */
        lis     r9,__got2_start@ha
        addi    r9,r9,__got2_start@l
        lis     r8,__got2_end@ha
@@ -32,15 +38,14 @@ _zimage_start:
        srwi.   r8,r8,2
        mtctr   r8
        add     r9,r0,r9
-2:
-       lwz     r8,0(r9)
+2:     lwz     r8,0(r9)
        add     r8,r8,r0
        stw     r8,0(r9)
        addi    r9,r9,4
        bdnz    2b
 
-3:
-       lis     r9,_start@h
+       /* Do a cache flush for our text, in case OF didn't */
+3:     lis     r9,_start@h
        add     r9,r0,r9
        lis     r8,_etext@ha
        addi    r8,r8,_etext@l
diff --git a/arch/powerpc/boot/dummy.c b/arch/powerpc/boot/dummy.c
new file mode 100644 (file)
index 0000000..31dbf45
--- /dev/null
@@ -0,0 +1,4 @@
+int main(void)
+{
+       return 0;
+}
diff --git a/arch/powerpc/boot/hack-coff.c b/arch/powerpc/boot/hack-coff.c
new file mode 100644 (file)
index 0000000..5e5a657
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC     0x010b
+
+#define get_16be(x)    ((((unsigned char *)(x))[0] << 8) \
+                        + ((unsigned char *)(x))[1])
+#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \
+                        ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x)    ((((unsigned char *)(x))[0] << 24) \
+                        + (((unsigned char *)(x))[1] << 16) \
+                        + (((unsigned char *)(x))[2] << 8) \
+                        + ((unsigned char *)(x))[3])
+
+int
+main(int ac, char **av)
+{
+    int fd;
+    int i, nsect;
+    int aoutsz;
+    struct external_filehdr fhdr;
+    AOUTHDR aout;
+    struct external_scnhdr shdr;
+
+    if (ac != 2) {
+       fprintf(stderr, "Usage: hack-coff coff-file\n");
+       exit(1);
+    }
+    if ((fd = open(av[1], 2)) == -1) {
+       perror(av[2]);
+       exit(1);
+    }
+    if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+       goto readerr;
+    i = get_16be(fhdr.f_magic);
+    if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+       fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+       exit(1);
+    }
+    aoutsz = get_16be(fhdr.f_opthdr);
+    if (read(fd, &aout, aoutsz) != aoutsz)
+       goto readerr;
+    nsect = get_16be(fhdr.f_nscns);
+    for (i = 0; i < nsect; ++i) {
+       if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+           goto readerr;
+       if (strcmp(shdr.s_name, ".text") == 0) {
+           put_16be(aout.o_snentry, i+1);
+           put_16be(aout.o_sntext, i+1);
+       } else if (strcmp(shdr.s_name, ".data") == 0) {
+           put_16be(aout.o_sndata, i+1);
+       } else if (strcmp(shdr.s_name, ".bss") == 0) {
+           put_16be(aout.o_snbss, i+1);
+       }
+    }
+    put_16be(aout.magic, AOUT_MAGIC);
+    if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+       || write(fd, &aout, aoutsz) != aoutsz) {
+       fprintf(stderr, "%s: write error\n", av[1]);
+       exit(1);
+    }
+    close(fd);
+    exit(0);
+
+readerr:
+    fprintf(stderr, "%s: read error or file too short\n", av[1]);
+    exit(1);
+}
index 64ec93116fa6cfb2d1eb6eed1578b80b61965487..55ec5986725079c24c56bef079c5f822700b9f0b 100644 (file)
@@ -21,8 +21,8 @@ extern void flush_cache(void *, unsigned long);
 
 
 /* Value picked to match that used by yaboot */
-#define PROG_START     0x01400000
-#define RAM_END                (512<<20) // Fixme: use OF */
+#define PROG_START     0x01400000      /* only used on 64-bit systems */
+#define RAM_END                (512<<20)       /* Fixme: use OF */
 #define        ONE_MB          0x100000
 
 extern char _start[];
@@ -160,6 +160,17 @@ static int is_elf64(void *hdr)
        elfoffset = (unsigned long)elf64ph->p_offset;
        vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
        vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
+
+#if defined(PROG_START)
+       /*
+        * Maintain a "magic" minimum address. This keeps some older
+        * firmware platforms running.
+        */
+
+       if (claim_base < PROG_START)
+               claim_base = PROG_START;
+#endif
+
        return 1;
 }
 
@@ -206,12 +217,18 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
                exit();
        if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
                exit();
-       stderr = stdout;
-       if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
-               exit();
 
        printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r", _start, sp);
 
+       /*
+        * The first available claim_base must be above the end of the
+        * the loaded kernel wrapper file (_start to _end includes the
+        * initrd image if it is present) and rounded up to a nice
+        * 1 MB boundary for good measure.
+        */
+
+       claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
+
        vmlinuz.addr = (unsigned long)_vmlinux_start;
        vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
 
@@ -228,25 +245,6 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
                exit();
        }
 
-       /*
-        * The first available claim_base must be above the end of the
-        * the loaded kernel wrapper file (_start to _end includes the
-        * initrd image if it is present) and rounded up to a nice
-        * 1 MB boundary for good measure.
-        */
-
-       claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
-
-#if defined(PROG_START)
-       /*
-        * Maintain a "magic" minimum address. This keeps some older
-        * firmware platforms running.
-        */
-
-       if (claim_base < PROG_START)
-               claim_base = PROG_START;
-#endif
-
        /* We need to claim 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
index 4bea2f4dcb067412be7610b23308a0d9c996302b..fa0057736f6b391bfc5fa96bfd5fdbebc217754d 100644 (file)
 #include "prom.h"
 
 int (*prom)(void *);
+phandle chosen_handle;
+ihandle stdout;
 
-void *chosen_handle;
-
-void *stdin;
-void *stdout;
-void *stderr;
-
-
-int
-write(void *handle, void *ptr, int nb)
-{
-       struct prom_args {
-               char *service;
-               int nargs;
-               int nret;
-               void *ihandle;
-               void *addr;
-               int len;
-               int actual;
-       } args;
-
-       args.service = "write";
-       args.nargs = 3;
-       args.nret = 1;
-       args.ihandle = handle;
-       args.addr = ptr;
-       args.len = nb;
-       args.actual = -1;
-       (*prom)(&args);
-       return args.actual;
-}
-
-int
-read(void *handle, void *ptr, int nb)
+int call_prom(const char *service, int nargs, int nret, ...)
 {
+       int i;
        struct prom_args {
-               char *service;
+               const char *service;
                int nargs;
                int nret;
-               void *ihandle;
-               void *addr;
-               int len;
-               int actual;
-       } args;
-
-       args.service = "read";
-       args.nargs = 3;
-       args.nret = 1;
-       args.ihandle = handle;
-       args.addr = ptr;
-       args.len = nb;
-       args.actual = -1;
-       (*prom)(&args);
-       return args.actual;
-}
-
-void
-exit()
-{
-       struct prom_args {
-               char *service;
-       } args;
-
-       for (;;) {
-               args.service = "exit";
-               (*prom)(&args);
-       }
-}
-
-void
-pause(void)
-{
-       struct prom_args {
-               char *service;
+               unsigned int args[12];
        } args;
+       va_list list;
 
-       args.service = "enter";
-       (*prom)(&args);
-}
+       args.service = service;
+       args.nargs = nargs;
+       args.nret = nret;
 
-void *
-finddevice(const char *name)
-{
-       struct prom_args {
-               char *service;
-               int nargs;
-               int nret;
-               const char *devspec;
-               void *phandle;
-       } args;
+       va_start(list, nret);
+       for (i = 0; i < nargs; i++)
+               args.args[i] = va_arg(list, unsigned int);
+       va_end(list);
 
-       args.service = "finddevice";
-       args.nargs = 1;
-       args.nret = 1;
-       args.devspec = name;
-       args.phandle = (void *) -1;
-       (*prom)(&args);
-       return args.phandle;
-}
+       for (i = 0; i < nret; i++)
+               args.args[nargs+i] = 0;
 
-void *
-claim(unsigned long virt, unsigned long size, unsigned long align)
-{
-       struct prom_args {
-               char *service;
-               int nargs;
-               int nret;
-               unsigned int virt;
-               unsigned int size;
-               unsigned int align;
-               void *ret;
-       } args;
+       if (prom(&args) < 0)
+               return -1;
 
-       args.service = "claim";
-       args.nargs = 3;
-       args.nret = 1;
-       args.virt = virt;
-       args.size = size;
-       args.align = align;
-       (*prom)(&args);
-       return args.ret;
+       return (nret > 0)? args.args[nargs]: 0;
 }
 
-int
-getprop(void *phandle, const char *name, void *buf, int buflen)
+int call_prom_ret(const char *service, int nargs, int nret,
+                 unsigned int *rets, ...)
 {
+       int i;
        struct prom_args {
-               char *service;
+               const char *service;
                int nargs;
                int nret;
-               void *phandle;
-               const char *name;
-               void *buf;
-               int buflen;
-               int size;
+               unsigned int args[12];
        } args;
+       va_list list;
 
-       args.service = "getprop";
-       args.nargs = 4;
-       args.nret = 1;
-       args.phandle = phandle;
-       args.name = name;
-       args.buf = buf;
-       args.buflen = buflen;
-       args.size = -1;
-       (*prom)(&args);
-       return args.size;
-}
+       args.service = service;
+       args.nargs = nargs;
+       args.nret = nret;
 
-int
-putc(int c, void *f)
-{
-       char ch = c;
+       va_start(list, rets);
+       for (i = 0; i < nargs; i++)
+               args.args[i] = va_arg(list, unsigned int);
+       va_end(list);
 
-       if (c == '\n')
-               putc('\r', f);
-       return write(f, &ch, 1) == 1? c: -1;
-}
+       for (i = 0; i < nret; i++)
+               args.args[nargs+i] = 0;
 
-int
-putchar(int c)
-{
-       return putc(c, stdout);
-}
+       if (prom(&args) < 0)
+               return -1;
 
-int
-fputs(char *str, void *f)
-{
-       int n = strlen(str);
+       if (rets != (void *) 0)
+               for (i = 1; i < nret; ++i)
+                       rets[i-1] = args.args[nargs+i];
 
-       return write(f, str, n) == n? 0: -1;
+       return (nret > 0)? args.args[nargs]: 0;
 }
 
-size_t strnlen(const char * s, size_t count)
+int write(void *handle, void *ptr, int nb)
 {
-       const char *sc;
-
-       for (sc = s; count-- && *sc != '\0'; ++sc)
-               /* nothing */;
-       return sc - s;
+       return call_prom("write", 3, 1, handle, ptr, nb);
 }
 
-extern unsigned int __div64_32(unsigned long long *dividend,
-                              unsigned int divisor);
-
-/* The unnecessary pointer compare is there
- * to check for type safety (n must be 64bit)
+/*
+ * Older OF's require that when claiming a specific range of addresses,
+ * we claim the physical space in the /memory node and the virtual
+ * space in the chosen mmu node, and then do a map operation to
+ * map virtual to physical.
  */
-# define do_div(n,base) ({                                             \
-       unsigned int __base = (base);                                   \
-       unsigned int __rem;                                             \
-       (void)(((typeof((n)) *)0) == ((unsigned long long *)0));        \
-       if (((n) >> 32) == 0) {                                         \
-               __rem = (unsigned int)(n) % __base;                     \
-               (n) = (unsigned int)(n) / __base;                       \
-       } else                                                          \
-               __rem = __div64_32(&(n), __base);                       \
-       __rem;                                                          \
- })
+static int need_map = -1;
+static ihandle chosen_mmu;
+static phandle memory;
 
-static int skip_atoi(const char **s)
+/* returns true if s2 is a prefix of s1 */
+static int string_match(const char *s1, const char *s2)
 {
-       int i, c;
-
-       for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
-               i = i*10 + c - '0';
-       return i;
+       for (; *s2; ++s2)
+               if (*s1++ != *s2)
+                       return 0;
+       return 1;
 }
 
-#define ZEROPAD        1               /* pad with zero */
-#define SIGN   2               /* unsigned/signed long */
-#define PLUS   4               /* show plus */
-#define SPACE  8               /* space if plus */
-#define LEFT   16              /* left justified */
-#define SPECIAL        32              /* 0x */
-#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
-
-static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
+static int check_of_version(void)
 {
-       char c,sign,tmp[66];
-       const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
-       int i;
+       phandle oprom, chosen;
+       char version[64];
 
-       if (type & LARGE)
-               digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-       if (type & LEFT)
-               type &= ~ZEROPAD;
-       if (base < 2 || base > 36)
+       oprom = finddevice("/openprom");
+       if (oprom == (phandle) -1)
                return 0;
-       c = (type & ZEROPAD) ? '0' : ' ';
-       sign = 0;
-       if (type & SIGN) {
-               if ((signed long long)num < 0) {
-                       sign = '-';
-                       num = - (signed long long)num;
-                       size--;
-               } else if (type & PLUS) {
-                       sign = '+';
-                       size--;
-               } else if (type & SPACE) {
-                       sign = ' ';
-                       size--;
+       if (getprop(oprom, "model", version, sizeof(version)) <= 0)
+               return 0;
+       version[sizeof(version)-1] = 0;
+       printf("OF version = '%s'\r\n", version);
+       if (!string_match(version, "Open Firmware, 1.")
+           && !string_match(version, "FirmWorks,3."))
+               return 0;
+       chosen = finddevice("/chosen");
+       if (chosen == (phandle) -1) {
+               chosen = finddevice("/chosen@0");
+               if (chosen == (phandle) -1) {
+                       printf("no chosen\n");
+                       return 0;
                }
        }
-       if (type & SPECIAL) {
-               if (base == 16)
-                       size -= 2;
-               else if (base == 8)
-                       size--;
-       }
-       i = 0;
-       if (num == 0)
-               tmp[i++]='0';
-       else while (num != 0) {
-               tmp[i++] = digits[do_div(num, base)];
+       if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+               printf("no mmu\n");
+               return 0;
        }
-       if (i > precision)
-               precision = i;
-       size -= precision;
-       if (!(type&(ZEROPAD+LEFT)))
-               while(size-->0)
-                       *str++ = ' ';
-       if (sign)
-               *str++ = sign;
-       if (type & SPECIAL) {
-               if (base==8)
-                       *str++ = '0';
-               else if (base==16) {
-                       *str++ = '0';
-                       *str++ = digits[33];
+       memory = (ihandle) call_prom("open", 1, 1, "/memory");
+       if (memory == (ihandle) -1) {
+               memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
+               if (memory == (ihandle) -1) {
+                       printf("no memory node\n");
+                       return 0;
                }
        }
-       if (!(type & LEFT))
-               while (size-- > 0)
-                       *str++ = c;
-       while (i < precision--)
-               *str++ = '0';
-       while (i-- > 0)
-               *str++ = tmp[i];
-       while (size-- > 0)
-               *str++ = ' ';
-       return str;
+       printf("old OF detected\r\n");
+       return 1;
 }
 
-int vsprintf(char *buf, const char *fmt, va_list args)
+void *claim(unsigned long virt, unsigned long size, unsigned long align)
 {
-       int len;
-       unsigned long long num;
-       int i, base;
-       char * str;
-       const char *s;
-
-       int flags;              /* flags to number() */
-
-       int field_width;        /* width of output field */
-       int precision;          /* min. # of digits for integers; max
-                                  number of chars for from string */
-       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
-                               /* 'z' support added 23/7/1999 S.H.    */
-                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+       int ret;
+       unsigned int result;
 
+       if (need_map < 0)
+               need_map = check_of_version();
+       if (align || !need_map)
+               return (void *) call_prom("claim", 3, 1, virt, size, align);
        
-       for (str=buf ; *fmt ; ++fmt) {
-               if (*fmt != '%') {
-                       *str++ = *fmt;
-                       continue;
-               }
-                       
-               /* process flags */
-               flags = 0;
-               repeat:
-                       ++fmt;          /* this also skips first '%' */
-                       switch (*fmt) {
-                               case '-': flags |= LEFT; goto repeat;
-                               case '+': flags |= PLUS; goto repeat;
-                               case ' ': flags |= SPACE; goto repeat;
-                               case '#': flags |= SPECIAL; goto repeat;
-                               case '0': flags |= ZEROPAD; goto repeat;
-                               }
-               
-               /* get field width */
-               field_width = -1;
-               if ('0' <= *fmt && *fmt <= '9')
-                       field_width = skip_atoi(&fmt);
-               else if (*fmt == '*') {
-                       ++fmt;
-                       /* it's the next argument */
-                       field_width = va_arg(args, int);
-                       if (field_width < 0) {
-                               field_width = -field_width;
-                               flags |= LEFT;
-                       }
-               }
-
-               /* get the precision */
-               precision = -1;
-               if (*fmt == '.') {
-                       ++fmt;  
-                       if ('0' <= *fmt && *fmt <= '9')
-                               precision = skip_atoi(&fmt);
-                       else if (*fmt == '*') {
-                               ++fmt;
-                               /* it's the next argument */
-                               precision = va_arg(args, int);
-                       }
-                       if (precision < 0)
-                               precision = 0;
-               }
-
-               /* get the conversion qualifier */
-               qualifier = -1;
-               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
-                       qualifier = *fmt;
-                       ++fmt;
-               }
-
-               /* default base */
-               base = 10;
-
-               switch (*fmt) {
-               case 'c':
-                       if (!(flags & LEFT))
-                               while (--field_width > 0)
-                                       *str++ = ' ';
-                       *str++ = (unsigned char) va_arg(args, int);
-                       while (--field_width > 0)
-                               *str++ = ' ';
-                       continue;
-
-               case 's':
-                       s = va_arg(args, char *);
-                       if (!s)
-                               s = "<NULL>";
-
-                       len = strnlen(s, precision);
-
-                       if (!(flags & LEFT))
-                               while (len < field_width--)
-                                       *str++ = ' ';
-                       for (i = 0; i < len; ++i)
-                               *str++ = *s++;
-                       while (len < field_width--)
-                               *str++ = ' ';
-                       continue;
-
-               case 'p':
-                       if (field_width == -1) {
-                               field_width = 2*sizeof(void *);
-                               flags |= ZEROPAD;
-                       }
-                       str = number(str,
-                               (unsigned long) va_arg(args, void *), 16,
-                               field_width, precision, flags);
-                       continue;
-
-
-               case 'n':
-                       if (qualifier == 'l') {
-                               long * ip = va_arg(args, long *);
-                               *ip = (str - buf);
-                       } else if (qualifier == 'Z') {
-                               size_t * ip = va_arg(args, size_t *);
-                               *ip = (str - buf);
-                       } else {
-                               int * ip = va_arg(args, int *);
-                               *ip = (str - buf);
-                       }
-                       continue;
-
-               case '%':
-                       *str++ = '%';
-                       continue;
-
-               /* integer number formats - set up the flags and "break" */
-               case 'o':
-                       base = 8;
-                       break;
-
-               case 'X':
-                       flags |= LARGE;
-               case 'x':
-                       base = 16;
-                       break;
-
-               case 'd':
-               case 'i':
-                       flags |= SIGN;
-               case 'u':
-                       break;
-
-               default:
-                       *str++ = '%';
-                       if (*fmt)
-                               *str++ = *fmt;
-                       else
-                               --fmt;
-                       continue;
-               }
-               if (qualifier == 'l') {
-                       num = va_arg(args, unsigned long);
-                       if (flags & SIGN)
-                               num = (signed long) num;
-               } else if (qualifier == 'Z') {
-                       num = va_arg(args, size_t);
-               } else if (qualifier == 'h') {
-                       num = (unsigned short) va_arg(args, int);
-                       if (flags & SIGN)
-                               num = (signed short) num;
-               } else {
-                       num = va_arg(args, unsigned int);
-                       if (flags & SIGN)
-                               num = (signed int) num;
-               }
-               str = number(str, num, base, field_width, precision, flags);
-       }
-       *str = '\0';
-       return str-buf;
-}
-
-int sprintf(char * buf, const char *fmt, ...)
-{
-       va_list args;
-       int i;
-
-       va_start(args, fmt);
-       i=vsprintf(buf,fmt,args);
-       va_end(args);
-       return i;
-}
-
-static char sprint_buf[1024];
-
-int
-printf(const char *fmt, ...)
-{
-       va_list args;
-       int n;
-
-       va_start(args, fmt);
-       n = vsprintf(sprint_buf, fmt, args);
-       va_end(args);
-       write(stdout, sprint_buf, n);
-       return n;
+       ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
+                           align, size, virt);
+       if (ret != 0 || result == -1)
+               return (void *) -1;
+       ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
+                           align, size, virt);
+       /* 0x12 == coherent + read/write */
+       ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
+                       0x12, size, virt, virt);
+       return (void *) virt;
 }
index 96ab5aec740c6cb20682736ec83663b134f0dc90..3e2ddd4a5a816ffeee35883847bffbd617fd2411 100644 (file)
@@ -1,18 +1,34 @@
 #ifndef _PPC_BOOT_PROM_H_
 #define _PPC_BOOT_PROM_H_
 
+typedef void *phandle;
+typedef void *ihandle;
+
 extern int (*prom) (void *);
-extern void *chosen_handle;
+extern phandle chosen_handle;
+extern ihandle stdout;
 
-extern void *stdin;
-extern void *stdout;
-extern void *stderr;
+int    call_prom(const char *service, int nargs, int nret, ...);
+int    call_prom_ret(const char *service, int nargs, int nret,
+                     unsigned int *rets, ...);
 
 extern int write(void *handle, void *ptr, int nb);
-extern int read(void *handle, void *ptr, int nb);
-extern void exit(void);
-extern void pause(void);
-extern void *finddevice(const char *);
-extern void *claim(unsigned long virt, unsigned long size, unsigned long align);
-extern int getprop(void *phandle, const char *name, void *buf, int buflen);
+extern void *claim(unsigned long virt, unsigned long size, unsigned long aln);
+
+static inline void exit(void)
+{
+       call_prom("exit", 0, 0);
+}
+
+static inline phandle finddevice(const char *name)
+{
+       return (phandle) call_prom("finddevice", 1, 1, name);
+}
+
+static inline int getprop(void *phandle, const char *name,
+                         void *buf, int buflen)
+{
+       return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
+}
+
 #endif                         /* _PPC_BOOT_PROM_H_ */
diff --git a/arch/powerpc/boot/rs6000.h b/arch/powerpc/boot/rs6000.h
new file mode 100644 (file)
index 0000000..433f450
--- /dev/null
@@ -0,0 +1,243 @@
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+   Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+   FIXME: Can someone provide a transliteration of this name into ASCII?
+   Using the following chars caused a compiler warning on HIUX (so I replaced
+   them with octal escapes), and isn't useful without an understanding of what
+   character set it is.
+   Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+   and John Gilmore of Cygnus Support.  */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+       char f_magic[2];        /* magic number                 */
+       char f_nscns[2];        /* number of sections           */
+       char f_timdat[4];       /* time & date stamp            */
+       char f_symptr[4];       /* file pointer to symtab       */
+       char f_nsyms[4];        /* number of symtab entries     */
+       char f_opthdr[2];       /* sizeof(optional hdr)         */
+       char f_flags[2];        /* flags                        */
+};
+
+        /* IBM RS/6000 */
+#define U802WRMAGIC     0730    /* writeable text segments **chh**      */
+#define U802ROMAGIC     0735    /* readonly sharable text segments      */
+#define U802TOCMAGIC    0737    /* readonly text segments and TOC       */
+
+#define BADMAG(x)      \
+       ((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+        (x).f_magic != U802TOCMAGIC)
+
+#define        FILHDR  struct external_filehdr
+#define        FILHSZ  20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct
+{
+  unsigned char        magic[2];       /* type of file                 */
+  unsigned char        vstamp[2];      /* version stamp                */
+  unsigned char        tsize[4];       /* text size in bytes, padded to FW bdry */
+  unsigned char        dsize[4];       /* initialized data "  "        */
+  unsigned char        bsize[4];       /* uninitialized data "   "     */
+  unsigned char        entry[4];       /* entry pt.                    */
+  unsigned char        text_start[4];  /* base of text used for this file */
+  unsigned char        data_start[4];  /* base of data used for this file */
+  unsigned char        o_toc[4];       /* address of TOC */
+  unsigned char        o_snentry[2];   /* section number of entry point */
+  unsigned char        o_sntext[2];    /* section number of .text section */
+  unsigned char        o_sndata[2];    /* section number of .data section */
+  unsigned char        o_sntoc[2];     /* section number of TOC */
+  unsigned char        o_snloader[2];  /* section number of .loader section */
+  unsigned char        o_snbss[2];     /* section number of .bss section */
+  unsigned char        o_algntext[2];  /* .text alignment */
+  unsigned char        o_algndata[2];  /* .data alignment */
+  unsigned char        o_modtype[2];   /* module type (??) */
+  unsigned char o_cputype[2];  /* cpu type */
+  unsigned char        o_maxstack[4];  /* max stack size (??) */
+  unsigned char o_maxdata[4];  /* max data size (??) */
+  unsigned char        o_resv2[12];    /* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define        RS6K_AOUTHDR_OMAGIC     0x0107  /* old: text & data writeable */
+#define        RS6K_AOUTHDR_NMAGIC     0x0108  /* new: text r/o, data r/w */
+#define        RS6K_AOUTHDR_ZMAGIC     0x010B  /* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+       char            s_name[8];      /* section name                 */
+       char            s_paddr[4];     /* physical address, aliased s_nlib */
+       char            s_vaddr[4];     /* virtual address              */
+       char            s_size[4];      /* section size                 */
+       char            s_scnptr[4];    /* file ptr to raw data for section */
+       char            s_relptr[4];    /* file ptr to relocation       */
+       char            s_lnnoptr[4];   /* file ptr to line numbers     */
+       char            s_nreloc[2];    /* number of relocation entries */
+       char            s_nlnno[2];     /* number of line number entries*/
+       char            s_flags[4];     /* flags                        */
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT  ".text"
+#define _DATA  ".data"
+#define _BSS   ".bss"
+#define _PAD   ".pad"
+#define _LOADER        ".loader"
+
+#define        SCNHDR  struct external_scnhdr
+#define        SCNHSZ  40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER.  */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG.  */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+   another section header with STYP_OVRFLO set.  */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+       union {
+               char l_symndx[4];       /* function name symbol index, iff l_lnno == 0*/
+               char l_paddr[4];        /* (physical) address of line number    */
+       } l_addr;
+       char l_lnno[2]; /* line number          */
+};
+
+
+#define        LINENO  struct external_lineno
+#define        LINESZ  6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN     8       /* # characters in a symbol name        */
+#define E_FILNMLEN     14      /* # characters in a file name          */
+#define E_DIMNUM       4       /* # array dimensions in auxiliary entry */
+
+struct external_syment
+{
+  union {
+    char e_name[E_SYMNMLEN];
+    struct {
+      char e_zeroes[4];
+      char e_offset[4];
+    } e;
+  } e;
+  char e_value[4];
+  char e_scnum[2];
+  char e_type[2];
+  char e_sclass[1];
+  char e_numaux[1];
+};
+
+
+
+#define N_BTMASK       (017)
+#define N_TMASK                (060)
+#define N_BTSHFT       (4)
+#define N_TSHIFT       (2)
+
+
+union external_auxent {
+       struct {
+               char x_tagndx[4];       /* str, un, or enum tag indx */
+               union {
+                       struct {
+                           char  x_lnno[2]; /* declaration line number */
+                           char  x_size[2]; /* str/union/array size */
+                       } x_lnsz;
+                       char x_fsize[4];        /* size of function */
+               } x_misc;
+               union {
+                       struct {                /* if ISFCN, tag, or .bb */
+                           char x_lnnoptr[4];  /* ptr to fcn line # */
+                           char x_endndx[4];   /* entry ndx past block end */
+                       } x_fcn;
+                       struct {                /* if ISARY, up to 4 dimen. */
+                           char x_dimen[E_DIMNUM][2];
+                       } x_ary;
+               } x_fcnary;
+               char x_tvndx[2];                /* tv index */
+       } x_sym;
+
+       union {
+               char x_fname[E_FILNMLEN];
+               struct {
+                       char x_zeroes[4];
+                       char x_offset[4];
+               } x_n;
+       } x_file;
+
+       struct {
+               char x_scnlen[4];                       /* section length */
+               char x_nreloc[2];       /* # relocation entries */
+               char x_nlinno[2];       /* # line numbers */
+       } x_scn;
+
+        struct {
+               char x_tvfill[4];       /* tv fill value */
+               char x_tvlen[2];        /* length of .tv */
+               char x_tvran[2][2];     /* tv range */
+       } x_tv;         /* info about .tv section (in auxent of symbol .tv)) */
+
+       struct {
+               unsigned char x_scnlen[4];
+               unsigned char x_parmhash[4];
+               unsigned char x_snhash[2];
+               unsigned char x_smtyp[1];
+               unsigned char x_smclas[1];
+               unsigned char x_stab[4];
+               unsigned char x_snstab[2];
+       } x_csect;
+
+};
+
+#define        SYMENT  struct external_syment
+#define        SYMESZ  18
+#define        AUXENT  union external_auxent
+#define        AUXESZ  18
+#define DBXMASK 0x80           /* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+  char r_vaddr[4];
+  char r_symndx[4];
+  char r_size[1];
+  char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
new file mode 100644 (file)
index 0000000..b5aa522
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "prom.h"
+
+size_t strnlen(const char * s, size_t count)
+{
+       const char *sc;
+
+       for (sc = s; count-- && *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+extern unsigned int __div64_32(unsigned long long *dividend,
+                              unsigned int divisor);
+
+/* The unnecessary pointer compare is there
+ * to check for type safety (n must be 64bit)
+ */
+# define do_div(n,base) ({                                             \
+       unsigned int __base = (base);                                   \
+       unsigned int __rem;                                             \
+       (void)(((typeof((n)) *)0) == ((unsigned long long *)0));        \
+       if (((n) >> 32) == 0) {                                         \
+               __rem = (unsigned int)(n) % __base;                     \
+               (n) = (unsigned int)(n) / __base;                       \
+       } else                                                          \
+               __rem = __div64_32(&(n), __base);                       \
+       __rem;                                                          \
+ })
+
+static int skip_atoi(const char **s)
+{
+       int i, c;
+
+       for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
+               i = i*10 + c - '0';
+       return i;
+}
+
+#define ZEROPAD        1               /* pad with zero */
+#define SIGN   2               /* unsigned/signed long */
+#define PLUS   4               /* show plus */
+#define SPACE  8               /* space if plus */
+#define LEFT   16              /* left justified */
+#define SPECIAL        32              /* 0x */
+#define LARGE  64              /* use 'ABCDEF' instead of 'abcdef' */
+
+static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
+{
+       char c,sign,tmp[66];
+       const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+       int i;
+
+       if (type & LARGE)
+               digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+       if (type & LEFT)
+               type &= ~ZEROPAD;
+       if (base < 2 || base > 36)
+               return 0;
+       c = (type & ZEROPAD) ? '0' : ' ';
+       sign = 0;
+       if (type & SIGN) {
+               if ((signed long long)num < 0) {
+                       sign = '-';
+                       num = - (signed long long)num;
+                       size--;
+               } else if (type & PLUS) {
+                       sign = '+';
+                       size--;
+               } else if (type & SPACE) {
+                       sign = ' ';
+                       size--;
+               }
+       }
+       if (type & SPECIAL) {
+               if (base == 16)
+                       size -= 2;
+               else if (base == 8)
+                       size--;
+       }
+       i = 0;
+       if (num == 0)
+               tmp[i++]='0';
+       else while (num != 0) {
+               tmp[i++] = digits[do_div(num, base)];
+       }
+       if (i > precision)
+               precision = i;
+       size -= precision;
+       if (!(type&(ZEROPAD+LEFT)))
+               while(size-->0)
+                       *str++ = ' ';
+       if (sign)
+               *str++ = sign;
+       if (type & SPECIAL) {
+               if (base==8)
+                       *str++ = '0';
+               else if (base==16) {
+                       *str++ = '0';
+                       *str++ = digits[33];
+               }
+       }
+       if (!(type & LEFT))
+               while (size-- > 0)
+                       *str++ = c;
+       while (i < precision--)
+               *str++ = '0';
+       while (i-- > 0)
+               *str++ = tmp[i];
+       while (size-- > 0)
+               *str++ = ' ';
+       return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+       int len;
+       unsigned long long num;
+       int i, base;
+       char * str;
+       const char *s;
+
+       int flags;              /* flags to number() */
+
+       int field_width;        /* width of output field */
+       int precision;          /* min. # of digits for integers; max
+                                  number of chars for from string */
+       int qualifier;          /* 'h', 'l', or 'L' for integer fields */
+                               /* 'z' support added 23/7/1999 S.H.    */
+                               /* 'z' changed to 'Z' --davidm 1/25/99 */
+
+       
+       for (str=buf ; *fmt ; ++fmt) {
+               if (*fmt != '%') {
+                       *str++ = *fmt;
+                       continue;
+               }
+                       
+               /* process flags */
+               flags = 0;
+               repeat:
+                       ++fmt;          /* this also skips first '%' */
+                       switch (*fmt) {
+                               case '-': flags |= LEFT; goto repeat;
+                               case '+': flags |= PLUS; goto repeat;
+                               case ' ': flags |= SPACE; goto repeat;
+                               case '#': flags |= SPECIAL; goto repeat;
+                               case '0': flags |= ZEROPAD; goto repeat;
+                               }
+               
+               /* get field width */
+               field_width = -1;
+               if ('0' <= *fmt && *fmt <= '9')
+                       field_width = skip_atoi(&fmt);
+               else if (*fmt == '*') {
+                       ++fmt;
+                       /* it's the next argument */
+                       field_width = va_arg(args, int);
+                       if (field_width < 0) {
+                               field_width = -field_width;
+                               flags |= LEFT;
+                       }
+               }
+
+               /* get the precision */
+               precision = -1;
+               if (*fmt == '.') {
+                       ++fmt;  
+                       if ('0' <= *fmt && *fmt <= '9')
+                               precision = skip_atoi(&fmt);
+                       else if (*fmt == '*') {
+                               ++fmt;
+                               /* it's the next argument */
+                               precision = va_arg(args, int);
+                       }
+                       if (precision < 0)
+                               precision = 0;
+               }
+
+               /* get the conversion qualifier */
+               qualifier = -1;
+               if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
+                       qualifier = *fmt;
+                       ++fmt;
+               }
+
+               /* default base */
+               base = 10;
+
+               switch (*fmt) {
+               case 'c':
+                       if (!(flags & LEFT))
+                               while (--field_width > 0)
+                                       *str++ = ' ';
+                       *str++ = (unsigned char) va_arg(args, int);
+                       while (--field_width > 0)
+                               *str++ = ' ';
+                       continue;
+
+               case 's':
+                       s = va_arg(args, char *);
+                       if (!s)
+                               s = "<NULL>";
+
+                       len = strnlen(s, precision);
+
+                       if (!(flags & LEFT))
+                               while (len < field_width--)
+                                       *str++ = ' ';
+                       for (i = 0; i < len; ++i)
+                               *str++ = *s++;
+                       while (len < field_width--)
+                               *str++ = ' ';
+                       continue;
+
+               case 'p':
+                       if (field_width == -1) {
+                               field_width = 2*sizeof(void *);
+                               flags |= ZEROPAD;
+                       }
+                       str = number(str,
+                               (unsigned long) va_arg(args, void *), 16,
+                               field_width, precision, flags);
+                       continue;
+
+
+               case 'n':
+                       if (qualifier == 'l') {
+                               long * ip = va_arg(args, long *);
+                               *ip = (str - buf);
+                       } else if (qualifier == 'Z') {
+                               size_t * ip = va_arg(args, size_t *);
+                               *ip = (str - buf);
+                       } else {
+                               int * ip = va_arg(args, int *);
+                               *ip = (str - buf);
+                       }
+                       continue;
+
+               case '%':
+                       *str++ = '%';
+                       continue;
+
+               /* integer number formats - set up the flags and "break" */
+               case 'o':
+                       base = 8;
+                       break;
+
+               case 'X':
+                       flags |= LARGE;
+               case 'x':
+                       base = 16;
+                       break;
+
+               case 'd':
+               case 'i':
+                       flags |= SIGN;
+               case 'u':
+                       break;
+
+               default:
+                       *str++ = '%';
+                       if (*fmt)
+                               *str++ = *fmt;
+                       else
+                               --fmt;
+                       continue;
+               }
+               if (qualifier == 'l') {
+                       num = va_arg(args, unsigned long);
+                       if (flags & SIGN)
+                               num = (signed long) num;
+               } else if (qualifier == 'Z') {
+                       num = va_arg(args, size_t);
+               } else if (qualifier == 'h') {
+                       num = (unsigned short) va_arg(args, int);
+                       if (flags & SIGN)
+                               num = (signed short) num;
+               } else {
+                       num = va_arg(args, unsigned int);
+                       if (flags & SIGN)
+                               num = (signed int) num;
+               }
+               str = number(str, num, base, field_width, precision, flags);
+       }
+       *str = '\0';
+       return str-buf;
+}
+
+int sprintf(char * buf, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i=vsprintf(buf,fmt,args);
+       va_end(args);
+       return i;
+}
+
+static char sprint_buf[1024];
+
+int
+printf(const char *fmt, ...)
+{
+       va_list args;
+       int n;
+
+       va_start(args, fmt);
+       n = vsprintf(sprint_buf, fmt, args);
+       va_end(args);
+       write(stdout, sprint_buf, n);
+       return n;
+}
index 24bd3a8dee949e18f019270553ce86963c036740..eb9e16c87aef793c380cea859a19674c2f035032 100644 (file)
@@ -7,10 +7,4 @@ extern int sprintf(char *buf, const char *fmt, ...);
 
 extern int vsprintf(char *buf, const char *fmt, va_list args);
 
-extern int putc(int c, void *f);
-extern int putchar(int c);
-extern int getchar(void);
-
-extern int fputs(char *str, void *f);
-
 #endif                         /* _PPC_BOOT_STDIO_H_ */
index b1eeaed7db177e273c6e014c4d0c882e82cee739..ac3d43b6a324c97549d8c181e2896ee2f41d377f 100644 (file)
@@ -107,10 +107,12 @@ memcpy:
        rlwinm. r7,r5,32-3,3,31         /* r7 = r5 >> 3 */
        addi    r6,r3,-4
        addi    r4,r4,-4
-       beq     2f                      /* if less than 8 bytes to do */
+       beq     3f                      /* if less than 8 bytes to do */
        andi.   r0,r6,3                 /* get dest word aligned */
        mtctr   r7
        bne     5f
+       andi.   r0,r4,3                 /* check src word aligned too */
+       bne     3f
 1:     lwz     r7,4(r4)
        lwzu    r8,8(r4)
        stw     r7,4(r6)
@@ -132,6 +134,11 @@ memcpy:
        bdnz    4b
        blr
 5:     subfic  r0,r0,4
+       cmpw    cr1,r0,r5
+       add     r7,r0,r4
+       andi.   r7,r7,3                 /* will source be word-aligned too? */
+       ble     cr1,3b
+       bne     3b                      /* do byte-by-byte if not */
        mtctr   r0
 6:     lbz     r7,4(r4)
        addi    r4,r4,1
@@ -149,10 +156,12 @@ backwards_memcpy:
        rlwinm. r7,r5,32-3,3,31         /* r7 = r5 >> 3 */
        add     r6,r3,r5
        add     r4,r4,r5
-       beq     2f
+       beq     3f
        andi.   r0,r6,3
        mtctr   r7
        bne     5f
+       andi.   r0,r4,3
+       bne     3f
 1:     lwz     r7,-4(r4)
        lwzu    r8,-8(r4)
        stw     r7,-4(r6)
@@ -171,7 +180,12 @@ backwards_memcpy:
        stbu    r0,-1(r6)
        bdnz    4b
        blr
-5:     mtctr   r0
+5:     cmpw    cr1,r0,r5
+       subf    r7,r0,r4
+       andi.   r7,r7,3
+       ble     cr1,3b
+       bne     3b
+       mtctr   r0
 6:     lbzu    r7,-1(r4)
        stbu    r7,-1(r6)
        bdnz    6b
diff --git a/arch/powerpc/boot/zImage.coff.lds b/arch/powerpc/boot/zImage.coff.lds
new file mode 100644 (file)
index 0000000..6016251
--- /dev/null
@@ -0,0 +1,46 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_start)
+SECTIONS
+{
+  . = (5*1024*1024);
+  _start = .;
+  .text      :
+  {
+    *(.text)
+    *(.fixup)
+  }
+  _etext = .;
+  . = ALIGN(4096);
+  .data    :
+  {
+    *(.rodata*)
+    *(.data*)
+    *(.sdata*)
+    __got2_start = .;
+    *(.got2)
+    __got2_end = .;
+
+    _vmlinux_start =  .;
+    *(.kernel:vmlinux.strip)
+    _vmlinux_end =  .;
+
+    _initrd_start =  .;
+    *(.kernel:initrd)
+    _initrd_end =  .;
+  }
+
+  . = ALIGN(4096);
+  _edata  =  .;
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss)
+   *(.bss)
+  }
+  _end = . ;
+
+  /DISCARD/ :
+  {
+    *(.comment)
+  }
+}
diff --git a/arch/powerpc/configs/mpc834x_sys_defconfig b/arch/powerpc/configs/mpc834x_sys_defconfig
new file mode 100644 (file)
index 0000000..3bff761
--- /dev/null
@@ -0,0 +1,911 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.15-g461d4edf-dirty
+# Fri Jan 13 11:01:47 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=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_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=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_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=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_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=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_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD 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_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+CONFIG_MPC834x_SYS=y
+CONFIG_MPC834x=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# 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_ARCH_FLATMEM_ENABLE=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_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC 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_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_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# 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_NET_DIVERT 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
+
+#
+# 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
+#
+
+#
+# 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=32768
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH 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
+
+#
+# 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
+
+#
+# Macintosh device drivers
+#
+# 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=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
+
+#
+# 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=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=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP 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_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_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO 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_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
+
+#
+# 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_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+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=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
+# 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
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK 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_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB 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_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID 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_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_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D 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
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB 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 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
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
+# 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_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_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# 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 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_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC 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_DES=y
+# 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_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# SEC2.x Options
+#
+CONFIG_MPC8349E_SEC2x=y
+
+#
+# SEC2.x Test Options
+#
+CONFIG_MPC8349E_SEC2xTEST=y
index 398203bd98eb32f4cf2e903b799b5f4b6f0205d5..2ace57d1e333ea5d17491747cc0cfc8be9223595 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-rc5
-# Tue Dec 13 17:24:05 2005
+# Linux kernel version: 2.6.15
+# Sat Jan 14 16:26:08 2006
 #
 # CONFIG_PPC64 is not set
 CONFIG_PPC32=y
@@ -15,11 +15,15 @@ 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_CRASH_DUMP is not set
+# CONFIG_GENERIC_TBSYNC is not set
 
 #
 # Processor support
 #
-CONFIG_6xx=y
+CONFIG_CLASSIC32=y
 # CONFIG_PPC_52xx is not set
 # CONFIG_PPC_82xx is not set
 # CONFIG_PPC_83xx is not set
@@ -28,6 +32,7 @@ CONFIG_6xx=y
 # CONFIG_8xx is not set
 # CONFIG_E200 is not set
 # CONFIG_E500 is not set
+CONFIG_6xx=y
 CONFIG_PPC_FPU=y
 CONFIG_ALTIVEC=y
 CONFIG_PPC_STD_MMU=y
@@ -53,17 +58,18 @@ CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 # CONFIG_EMBEDDED is not set
 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
@@ -72,8 +78,10 @@ CONFIG_CC_ALIGN_FUNCTIONS=0
 CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
 
 #
 # Loadable module support
@@ -113,13 +121,10 @@ CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_APUS is not set
 # CONFIG_PPC_CHRP is not set
 CONFIG_PPC_PMAC=y
-CONFIG_PPC_OF=y
 CONFIG_MPIC=y
 # CONFIG_PPC_RTAS is not set
 # CONFIG_MMIO_NVRAM is not set
-# CONFIG_CRASH_DUMP is not set
 CONFIG_PPC_MPC106=y
-# CONFIG_GENERIC_TBSYNC is not set
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_TABLE=y
 # CONFIG_CPU_FREQ_DEBUG is not set
@@ -195,6 +200,11 @@ CONFIG_CARDBUS=y
 # PC-card bridges
 #
 CONFIG_YENTA=m
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_TOSHIBA=y
 # CONFIG_PD6729 is not set
 # CONFIG_I82092 is not set
 CONFIG_PCCARD_NONSTATIC=m
@@ -464,7 +474,7 @@ CONFIG_IEEE80211_CRYPT_TKIP=m
 #
 # CONFIG_STANDALONE is not set
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+CONFIG_FW_LOADER=y
 # CONFIG_DEBUG_DRIVER is not set
 
 #
@@ -491,7 +501,7 @@ CONFIG_PROC_EVENTS=y
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
-CONFIG_MAC_FLOPPY=y
+CONFIG_MAC_FLOPPY=m
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -603,7 +613,7 @@ CONFIG_SCSI_CONSTANTS=y
 # SCSI Transport Attributes
 #
 CONFIG_SCSI_SPI_ATTRS=y
-# CONFIG_SCSI_FC_ATTRS is not set
+CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_ATTRS is not set
 
@@ -645,12 +655,7 @@ CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE is not set
 # CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
@@ -658,7 +663,7 @@ CONFIG_SCSI_QLA2XXX=y
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_MESH=y
 CONFIG_SCSI_MESH_SYNC_RATE=5
-CONFIG_SCSI_MESH_RESET_DELAY_MS=1000
+CONFIG_SCSI_MESH_RESET_DELAY_MS=4000
 CONFIG_SCSI_MAC53C94=y
 
 #
@@ -727,7 +732,6 @@ CONFIG_IEEE1394_SBP2=m
 CONFIG_IEEE1394_ETH1394=m
 CONFIG_IEEE1394_DV1394=m
 CONFIG_IEEE1394_RAWIO=m
-# CONFIG_IEEE1394_CMP is not set
 
 #
 # I2O device support
@@ -740,7 +744,7 @@ CONFIG_IEEE1394_RAWIO=m
 CONFIG_ADB=y
 CONFIG_ADB_CUDA=y
 CONFIG_ADB_PMU=y
-CONFIG_PMAC_APM_EMU=y
+CONFIG_PMAC_APM_EMU=m
 CONFIG_PMAC_MEDIABAY=y
 CONFIG_PMAC_BACKLIGHT=y
 CONFIG_INPUT_ADBHID=y
@@ -819,6 +823,7 @@ CONFIG_PCNET32=y
 # 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
@@ -978,14 +983,14 @@ CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_8250=m
 # CONFIG_SERIAL_8250_CS is not set
 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_CORE=m
-# CONFIG_SERIAL_PMACZILOG is not set
-# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_PMACZILOG=m
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -1058,7 +1063,7 @@ CONFIG_I2C_ALGOBIT=y
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
 # CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_KEYWEST=m
+CONFIG_I2C_POWERMAC=y
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
@@ -1160,7 +1165,6 @@ CONFIG_FB_ATY128=y
 CONFIG_FB_ATY=y
 CONFIG_FB_ATY_CT=y
 # CONFIG_FB_ATY_GENERIC_LCD is not set
-# CONFIG_FB_ATY_XL_INIT is not set
 CONFIG_FB_ATY_GX=y
 # CONFIG_FB_SAVAGE is not set
 # CONFIG_FB_SIS is not set
@@ -1169,7 +1173,6 @@ CONFIG_FB_ATY_GX=y
 CONFIG_FB_3DFX=y
 # CONFIG_FB_3DFX_ACCEL is not set
 # CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -1214,9 +1217,10 @@ CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
 CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
-CONFIG_SND_GENERIC_DRIVER=y
 
 #
 # Generic devices
@@ -1230,6 +1234,8 @@ CONFIG_SND_DUMMY=m
 #
 # PCI devices
 #
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS4000 is not set
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_ATIIXP is not set
 # CONFIG_SND_ATIIXP_MODEM is not set
@@ -1238,45 +1244,44 @@ CONFIG_SND_DUMMY=m
 # CONFIG_SND_AU8830 is not set
 # CONFIG_SND_AZT3328 is not set
 # CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
 # CONFIG_SND_EMU10K1 is not set
 # CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_HDSPM is not set
-# CONFIG_SND_TRIDENT is not set
-# CONFIG_SND_YMFPCI is not set
-# CONFIG_SND_AD1889 is not set
-# CONFIG_SND_ALS4000 is not set
-# CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_ENS1370 is not set
 # CONFIG_SND_ENS1371 is not set
 # CONFIG_SND_ES1938 is not set
 # CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
 # CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VIA82XX_MODEM is not set
 # CONFIG_SND_VX222 is not set
-# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_YMFPCI is not set
 
 #
 # ALSA PowerMac devices
 #
 CONFIG_SND_POWERMAC=m
-# CONFIG_SND_POWERMAC_AUTO_DRC is not set
+CONFIG_SND_POWERMAC_AUTO_DRC=y
 
 #
 # USB devices
@@ -1336,6 +1341,7 @@ CONFIG_USB_PRINTER=m
 # may also be needed; see USB_STORAGE Help for more information
 #
 # CONFIG_USB_STORAGE is not set
+# CONFIG_USB_LIBUSUAL is not set
 
 #
 # USB Input Devices
@@ -1355,6 +1361,7 @@ CONFIG_USB_HIDINPUT=y
 # 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=y
 
@@ -1501,6 +1508,7 @@ CONFIG_FS_MBCACHE=y
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
 # CONFIG_XFS_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
@@ -1540,6 +1548,7 @@ CONFIG_TMPFS=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 CONFIG_RELAYFS_FS=m
+# CONFIG_CONFIGFS_FS is not set
 
 #
 # Miscellaneous filesystems
@@ -1670,12 +1679,13 @@ CONFIG_OPROFILE=y
 # Kernel hacking
 #
 # CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_KERNEL=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1688,6 +1698,11 @@ CONFIG_XMON=y
 CONFIG_XMON_DEFAULT=y
 # CONFIG_BDI_SWITCH is not set
 CONFIG_BOOTX_TEXT=y
+# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
+# CONFIG_PPC_EARLY_DEBUG_G5 is not set
+# CONFIG_PPC_EARLY_DEBUG_RTAS is not set
+# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
+# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
 
 #
 # Security options
index a94699d8dc52b4d534264d9e95439080bc13451d..c287980b7e65f3551444053609f20528e1efadb6 100644 (file)
@@ -60,7 +60,8 @@ obj-$(CONFIG_MODULES)         += $(module-y)
 
 pci64-$(CONFIG_PPC64)          += pci_64.o pci_dn.o pci_iommu.o \
                                   pci_direct_iommu.o iomap.o
-obj-$(CONFIG_PCI)              += $(pci64-y)
+pci32-$(CONFIG_PPC32)          := pci_32.o
+obj-$(CONFIG_PCI)              += $(pci64-y) $(pci32-y)
 kexec-$(CONFIG_PPC64)          := machine_kexec_64.o crash.o
 kexec-$(CONFIG_PPC32)          := machine_kexec_32.o
 obj-$(CONFIG_KEXEC)            += machine_kexec.o $(kexec-y)
index 56399c5c931a94ef809a61b432ca82311327dceb..840aad43a98bd218f5c985214e483b5578d6b763 100644 (file)
@@ -135,7 +135,7 @@ int main(void)
        DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
        DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
        DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
-       DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
+       DEFINE(PACALPPACAPTR, offsetof(struct paca_struct, lppaca_ptr));
        DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
 
        DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
index cca942fe61154ecb9883cdc3c6e6007eade0f228..b61d86e7ceb6059c7e838927dc66c25244441f1e 100644 (file)
@@ -130,7 +130,7 @@ _GLOBAL(__save_cpu_setup)
        mfcr    r7
 
        /* Get storage ptr */
-       LOADADDR(r5,cpu_state_storage)
+       LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
 
        /* We only deal with 970 for now */
        mfspr   r0,SPRN_PVR
@@ -164,7 +164,7 @@ _GLOBAL(__restore_cpu_setup)
        /* Get storage ptr (FIXME when using anton reloc as we
         * are running with translation disabled here
         */
-       LOADADDR(r5,cpu_state_storage)
+       LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
 
        /* We only deal with 970 for now */
        mfspr   r0,SPRN_PVR
index 43c74a6b07b1502e5039f8d10ea2e9a3d1f2ade5..10696456a4c616d0d3900ec0b6370b9a2cb41402 100644 (file)
@@ -55,7 +55,8 @@ extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
 #define COMMON_USER_POWER4     (COMMON_USER_PPC64 | PPC_FEATURE_POWER4)
 #define COMMON_USER_POWER5     (COMMON_USER_PPC64 | PPC_FEATURE_POWER5)
 #define COMMON_USER_POWER5_PLUS        (COMMON_USER_PPC64 | PPC_FEATURE_POWER5_PLUS)
-
+#define COMMON_USER_BOOKE      (PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | \
+                                PPC_FEATURE_BOOKE)
 
 /* We only set the spe features if the kernel was compiled with
  * spe support
@@ -79,7 +80,8 @@ struct cpu_spec       cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
                .oprofile_cpu_type      = "ppc64/power3",
-               .oprofile_type          = RS64,
+               .oprofile_type          = PPC_OPROFILE_RS64,
+               .platform               = "power3",
        },
        {       /* Power3+ */
                .pvr_mask               = 0xffff0000,
@@ -92,7 +94,8 @@ struct cpu_spec       cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
                .oprofile_cpu_type      = "ppc64/power3",
-               .oprofile_type          = RS64,
+               .oprofile_type          = PPC_OPROFILE_RS64,
+               .platform               = "power3",
        },
        {       /* Northstar */
                .pvr_mask               = 0xffff0000,
@@ -105,7 +108,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_type          = RS64,
+               .oprofile_type          = PPC_OPROFILE_RS64,
+               .platform               = "rs64",
        },
        {       /* Pulsar */
                .pvr_mask               = 0xffff0000,
@@ -118,7 +122,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_type          = RS64,
+               .oprofile_type          = PPC_OPROFILE_RS64,
+               .platform               = "rs64",
        },
        {       /* I-star */
                .pvr_mask               = 0xffff0000,
@@ -131,7 +136,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_type          = RS64,
+               .oprofile_type          = PPC_OPROFILE_RS64,
+               .platform               = "rs64",
        },
        {       /* S-star */
                .pvr_mask               = 0xffff0000,
@@ -144,7 +150,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power3,
                .oprofile_cpu_type      = "ppc64/rs64",
-               .oprofile_type          = RS64,
+               .oprofile_type          = PPC_OPROFILE_RS64,
+               .platform               = "rs64",
        },
        {       /* Power4 */
                .pvr_mask               = 0xffff0000,
@@ -157,7 +164,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power4,
                .oprofile_cpu_type      = "ppc64/power4",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "power4",
        },
        {       /* Power4+ */
                .pvr_mask               = 0xffff0000,
@@ -170,7 +178,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_power4,
                .oprofile_cpu_type      = "ppc64/power4",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "power4",
        },
        {       /* PPC970 */
                .pvr_mask               = 0xffff0000,
@@ -184,7 +193,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "ppc970",
        },
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_PPC64) || defined(CONFIG_POWER4)
@@ -204,7 +214,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 8,
                .cpu_setup              = __setup_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "ppc970",
        },
 #endif /* defined(CONFIG_PPC64) || defined(CONFIG_POWER4) */
 #ifdef CONFIG_PPC64
@@ -219,7 +230,8 @@ struct cpu_spec     cpu_specs[] = {
                .dcache_bsize           = 128,
                .cpu_setup              = __setup_cpu_ppc970,
                .oprofile_cpu_type      = "ppc64/970",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "ppc970",
        },
        {       /* Power5 GR */
                .pvr_mask               = 0xffff0000,
@@ -232,7 +244,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
                .oprofile_cpu_type      = "ppc64/power5",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "power5",
        },
        {       /* Power5 GS */
                .pvr_mask               = 0xffff0000,
@@ -245,7 +258,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
                .oprofile_cpu_type      = "ppc64/power5+",
-               .oprofile_type          = POWER4,
+               .oprofile_type          = PPC_OPROFILE_POWER4,
+               .platform               = "power5+",
        },
        {       /* Cell Broadband Engine */
                .pvr_mask               = 0xffff0000,
@@ -257,6 +271,7 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 128,
                .dcache_bsize           = 128,
                .cpu_setup              = __setup_cpu_be,
+               .platform               = "ppc-cell-be",
        },
        {       /* default match */
                .pvr_mask               = 0x00000000,
@@ -268,6 +283,7 @@ struct cpu_spec     cpu_specs[] = {
                .dcache_bsize           = 128,
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_power4,
+               .platform               = "power4",
        }
 #endif /* CONFIG_PPC64 */
 #ifdef CONFIG_PPC32
@@ -281,6 +297,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_UNIFIED_CACHE | PPC_FEATURE_NO_TB,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc601",
        },
        {       /* 603 */
                .pvr_mask               = 0xffff0000,
@@ -290,7 +307,8 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_603
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
        },
        {       /* 603e */
                .pvr_mask               = 0xffff0000,
@@ -300,7 +318,8 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_603
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
        },
        {       /* 603ev */
                .pvr_mask               = 0xffff0000,
@@ -310,7 +329,8 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_603
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
        },
        {       /* 604 */
                .pvr_mask               = 0xffff0000,
@@ -321,7 +341,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 2,
-               .cpu_setup              = __setup_cpu_604
+               .cpu_setup              = __setup_cpu_604,
+               .platform               = "ppc604",
        },
        {       /* 604e */
                .pvr_mask               = 0xfffff000,
@@ -332,7 +353,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_604
+               .cpu_setup              = __setup_cpu_604,
+               .platform               = "ppc604",
        },
        {       /* 604r */
                .pvr_mask               = 0xffff0000,
@@ -343,7 +365,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_604
+               .cpu_setup              = __setup_cpu_604,
+               .platform               = "ppc604",
        },
        {       /* 604ev */
                .pvr_mask               = 0xffff0000,
@@ -354,7 +377,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_604
+               .cpu_setup              = __setup_cpu_604,
+               .platform               = "ppc604",
        },
        {       /* 740/750 (0x4202, don't support TAU ?) */
                .pvr_mask               = 0xffffffff,
@@ -365,7 +389,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750
+               .cpu_setup              = __setup_cpu_750,
+               .platform               = "ppc750",
        },
        {       /* 750CX (80100 and 8010x?) */
                .pvr_mask               = 0xfffffff0,
@@ -376,7 +401,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750cx
+               .cpu_setup              = __setup_cpu_750cx,
+               .platform               = "ppc750",
        },
        {       /* 750CX (82201 and 82202) */
                .pvr_mask               = 0xfffffff0,
@@ -387,7 +413,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750cx
+               .cpu_setup              = __setup_cpu_750cx,
+               .platform               = "ppc750",
        },
        {       /* 750CXe (82214) */
                .pvr_mask               = 0xfffffff0,
@@ -398,7 +425,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750cx
+               .cpu_setup              = __setup_cpu_750cx,
+               .platform               = "ppc750",
        },
        {       /* 750CXe "Gekko" (83214) */
                .pvr_mask               = 0xffffffff,
@@ -409,7 +437,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750cx
+               .cpu_setup              = __setup_cpu_750cx,
+               .platform               = "ppc750",
        },
        {       /* 745/755 */
                .pvr_mask               = 0xfffff000,
@@ -420,7 +449,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750
+               .cpu_setup              = __setup_cpu_750,
+               .platform               = "ppc750",
        },
        {       /* 750FX rev 1.x */
                .pvr_mask               = 0xffffff00,
@@ -431,7 +461,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750
+               .cpu_setup              = __setup_cpu_750,
+               .platform               = "ppc750",
        },
        {       /* 750FX rev 2.0 must disable HID0[DPM] */
                .pvr_mask               = 0xffffffff,
@@ -442,7 +473,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750
+               .cpu_setup              = __setup_cpu_750,
+               .platform               = "ppc750",
        },
        {       /* 750FX (All revs except 2.0) */
                .pvr_mask               = 0xffff0000,
@@ -453,7 +485,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750fx
+               .cpu_setup              = __setup_cpu_750fx,
+               .platform               = "ppc750",
        },
        {       /* 750GX */
                .pvr_mask               = 0xffff0000,
@@ -464,7 +497,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750fx
+               .cpu_setup              = __setup_cpu_750fx,
+               .platform               = "ppc750",
        },
        {       /* 740/750 (L2CR bit need fixup for 740) */
                .pvr_mask               = 0xffff0000,
@@ -475,7 +509,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_750
+               .cpu_setup              = __setup_cpu_750,
+               .platform               = "ppc750",
        },
        {       /* 7400 rev 1.1 ? (no TAU) */
                .pvr_mask               = 0xffffffff,
@@ -486,7 +521,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_7400
+               .cpu_setup              = __setup_cpu_7400,
+               .platform               = "ppc7400",
        },
        {       /* 7400 */
                .pvr_mask               = 0xffff0000,
@@ -497,7 +533,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_7400
+               .cpu_setup              = __setup_cpu_7400,
+               .platform               = "ppc7400",
        },
        {       /* 7410 */
                .pvr_mask               = 0xffff0000,
@@ -508,7 +545,8 @@ struct cpu_spec     cpu_specs[] = {
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
-               .cpu_setup              = __setup_cpu_7410
+               .cpu_setup              = __setup_cpu_7410,
+               .platform               = "ppc7400",
        },
        {       /* 7450 2.0 - no doze/nap */
                .pvr_mask               = 0xffffffff,
@@ -521,7 +559,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7450 2.1 */
                .pvr_mask               = 0xffffffff,
@@ -534,7 +573,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7450 2.3 and newer */
                .pvr_mask               = 0xffff0000,
@@ -547,7 +587,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7455 rev 1.x */
                .pvr_mask               = 0xffffff00,
@@ -560,7 +601,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7455 rev 2.0 */
                .pvr_mask               = 0xffffffff,
@@ -573,7 +615,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7455 others */
                .pvr_mask               = 0xffff0000,
@@ -586,7 +629,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7447/7457 Rev 1.0 */
                .pvr_mask               = 0xffffffff,
@@ -599,7 +643,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7447/7457 Rev 1.1 */
                .pvr_mask               = 0xffffffff,
@@ -612,7 +657,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7447/7457 Rev 1.2 and later */
                .pvr_mask               = 0xffff0000,
@@ -625,7 +671,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7447A */
                .pvr_mask               = 0xffff0000,
@@ -638,7 +685,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 7448 */
                .pvr_mask               = 0xffff0000,
@@ -651,7 +699,8 @@ struct cpu_spec     cpu_specs[] = {
                .num_pmcs               = 6,
                .cpu_setup              = __setup_cpu_745x,
                .oprofile_cpu_type      = "ppc/7450",
-               .oprofile_type          = G4,
+               .oprofile_type          = PPC_OPROFILE_G4,
+               .platform               = "ppc7450",
        },
        {       /* 82xx (8240, 8245, 8260 are all 603e cores) */
                .pvr_mask               = 0x7fff0000,
@@ -661,7 +710,8 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_603
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
        },
        {       /* All G2_LE (603e core, plus some) have the same pvr */
                .pvr_mask               = 0x7fff0000,
@@ -671,7 +721,8 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_603
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
        },
        {       /* e300 (a 603e core, plus some) on 83xx */
                .pvr_mask               = 0x7fff0000,
@@ -681,7 +732,8 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
-               .cpu_setup              = __setup_cpu_603
+               .cpu_setup              = __setup_cpu_603,
+               .platform               = "ppc603",
        },
        {       /* default match, we assume split I/D cache & TB (non-601)... */
                .pvr_mask               = 0x00000000,
@@ -691,6 +743,7 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = COMMON_USER,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc603",
        },
 #endif /* CLASSIC_PPC */
 #ifdef CONFIG_8xx
@@ -704,6 +757,7 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
                .icache_bsize           = 16,
                .dcache_bsize           = 16,
+               .platform               = "ppc823",
        },
 #endif /* CONFIG_8xx */
 #ifdef CONFIG_40x
@@ -715,6 +769,7 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
                .icache_bsize           = 16,
                .dcache_bsize           = 16,
+               .platform               = "ppc403",
        },
        {       /* 403GCX */
                .pvr_mask               = 0xffffff00,
@@ -725,6 +780,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_NO_TB,
                .icache_bsize           = 16,
                .dcache_bsize           = 16,
+               .platform               = "ppc403",
        },
        {       /* 403G ?? */
                .pvr_mask               = 0xffff0000,
@@ -734,6 +790,7 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
                .icache_bsize           = 16,
                .dcache_bsize           = 16,
+               .platform               = "ppc403",
        },
        {       /* 405GP */
                .pvr_mask               = 0xffff0000,
@@ -744,6 +801,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* STB 03xxx */
                .pvr_mask               = 0xffff0000,
@@ -754,6 +812,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* STB 04xxx */
                .pvr_mask               = 0xffff0000,
@@ -764,6 +823,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* NP405L */
                .pvr_mask               = 0xffff0000,
@@ -774,6 +834,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* NP4GS3 */
                .pvr_mask               = 0xffff0000,
@@ -784,6 +845,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {   /* NP405H */
                .pvr_mask               = 0xffff0000,
@@ -794,6 +856,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* 405GPr */
                .pvr_mask               = 0xffff0000,
@@ -804,6 +867,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {   /* STBx25xx */
                .pvr_mask               = 0xffff0000,
@@ -814,6 +878,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* 405LP */
                .pvr_mask               = 0xffff0000,
@@ -823,6 +888,7 @@ struct cpu_spec     cpu_specs[] = {
                .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* Xilinx Virtex-II Pro  */
                .pvr_mask               = 0xffff0000,
@@ -833,6 +899,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
        {       /* 405EP */
                .pvr_mask               = 0xffff0000,
@@ -843,6 +910,7 @@ struct cpu_spec     cpu_specs[] = {
                        PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc405",
        },
 
 #endif /* CONFIG_40x */
@@ -852,81 +920,90 @@ struct cpu_spec   cpu_specs[] = {
                .pvr_value              = 0x40000850,
                .cpu_name               = "440EP Rev. A",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = COMMON_USER, /* 440EP has an FPU */
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        {
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x400008d3,
                .cpu_name               = "440EP Rev. B",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = COMMON_USER, /* 440EP has an FPU */
+               .cpu_user_features      = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        {       /* 440GP Rev. B */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x40000440,
                .cpu_name               = "440GP Rev. B",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440gp",
        },
        {       /* 440GP Rev. C */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x40000481,
                .cpu_name               = "440GP Rev. C",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440gp",
        },
        { /* 440GX Rev. A */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x50000850,
                .cpu_name               = "440GX Rev. A",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        { /* 440GX Rev. B */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x50000851,
                .cpu_name               = "440GX Rev. B",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        { /* 440GX Rev. C */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x50000892,
                .cpu_name               = "440GX Rev. C",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        { /* 440GX Rev. F */
                .pvr_mask               = 0xf0000fff,
                .pvr_value              = 0x50000894,
                .cpu_name               = "440GX Rev. F",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        { /* 440SP Rev. A */
                .pvr_mask               = 0xff000fff,
                .pvr_value              = 0x53000891,
                .cpu_name               = "440SP Rev. A",
                .cpu_features           = CPU_FTRS_44X,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
        { /* 440SPe Rev. A */
                .pvr_mask               = 0xff000fff,
@@ -934,9 +1011,10 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_name               = "440SPe Rev. A",
                .cpu_features           = CPU_FTR_SPLIT_ID_CACHE |
                        CPU_FTR_USE_TB,
-               .cpu_user_features      = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+               .cpu_user_features      = COMMON_USER_BOOKE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "ppc440",
        },
 #endif /* CONFIG_44x */
 #ifdef CONFIG_FSL_BOOKE
@@ -946,10 +1024,11 @@ struct cpu_spec  cpu_specs[] = {
                .cpu_name               = "e200z5",
                /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
                .cpu_features           = CPU_FTRS_E200,
-               .cpu_user_features      = PPC_FEATURE_32 |
-                       PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE |
+               .cpu_user_features      = COMMON_USER_BOOKE |
+                       PPC_FEATURE_HAS_EFP_SINGLE |
                        PPC_FEATURE_UNIFIED_CACHE,
                .dcache_bsize           = 32,
+               .platform               = "ppc5554",
        },
        {       /* e200z6 */
                .pvr_mask               = 0xfff00000,
@@ -957,11 +1036,12 @@ struct cpu_spec  cpu_specs[] = {
                .cpu_name               = "e200z6",
                /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
                .cpu_features           = CPU_FTRS_E200,
-               .cpu_user_features      = PPC_FEATURE_32 |
-                       PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+               .cpu_user_features      = COMMON_USER_BOOKE |
+                       PPC_FEATURE_SPE_COMP |
                        PPC_FEATURE_HAS_EFP_SINGLE |
                        PPC_FEATURE_UNIFIED_CACHE,
                .dcache_bsize           = 32,
+               .platform               = "ppc5554",
        },
        {       /* e500 */
                .pvr_mask               = 0xffff0000,
@@ -969,14 +1049,15 @@ struct cpu_spec  cpu_specs[] = {
                .cpu_name               = "e500",
                /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
                .cpu_features           = CPU_FTRS_E500,
-               .cpu_user_features      = PPC_FEATURE_32 |
-                       PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+               .cpu_user_features      = COMMON_USER_BOOKE |
+                       PPC_FEATURE_SPE_COMP |
                        PPC_FEATURE_HAS_EFP_SINGLE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
-               .oprofile_type          = BOOKE,
+               .oprofile_type          = PPC_OPROFILE_BOOKE,
+               .platform               = "ppc8540",
        },
        {       /* e500v2 */
                .pvr_mask               = 0xffff0000,
@@ -984,14 +1065,16 @@ struct cpu_spec  cpu_specs[] = {
                .cpu_name               = "e500v2",
                /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
                .cpu_features           = CPU_FTRS_E500_2,
-               .cpu_user_features      = PPC_FEATURE_32 |
-                       PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
-                       PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE,
+               .cpu_user_features      = COMMON_USER_BOOKE |
+                       PPC_FEATURE_SPE_COMP |
+                       PPC_FEATURE_HAS_EFP_SINGLE |
+                       PPC_FEATURE_HAS_EFP_DOUBLE,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
                .num_pmcs               = 4,
                .oprofile_cpu_type      = "ppc/e500",
-               .oprofile_type          = BOOKE,
+               .oprofile_type          = PPC_OPROFILE_BOOKE,
+               .platform               = "ppc8548",
        },
 #endif
 #if !CLASSIC_PPC
@@ -1003,6 +1086,7 @@ struct cpu_spec   cpu_specs[] = {
                .cpu_user_features      = PPC_FEATURE_32,
                .icache_bsize           = 32,
                .dcache_bsize           = 32,
+               .platform               = "powerpc",
        }
 #endif /* !CLASSIC_PPC */
 #endif /* CONFIG_PPC32 */
index 5f248e3fdf821abfc71a3041a3569762c2d4807d..8c21d378f5d2f59d4b715e5fe7fafebbe94819ed 100644 (file)
@@ -84,7 +84,10 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
         * squirrelled away.  ELF notes happen to provide
         * all of that that no need to invent something new.
         */
-       buf = &crash_notes[cpu][0];
+       buf = (u32*)per_cpu_ptr(crash_notes, cpu);
+       if (!buf) 
+               return;
+
        memset(&prstatus, 0, sizeof(prstatus));
        prstatus.pr_pid = current->pid;
        elf_core_copy_regs(&prstatus.pr_reg, regs);
@@ -93,76 +96,6 @@ static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
        final_note(buf);
 }
 
-/* FIXME Merge this with xmon_save_regs ?? */
-static inline void crash_get_current_regs(struct pt_regs *regs)
-{
-       unsigned long tmp1, tmp2;
-
-       __asm__ __volatile__ (
-               "std    0,0(%2)\n"
-               "std    1,8(%2)\n"
-               "std    2,16(%2)\n"
-               "std    3,24(%2)\n"
-               "std    4,32(%2)\n"
-               "std    5,40(%2)\n"
-               "std    6,48(%2)\n"
-               "std    7,56(%2)\n"
-               "std    8,64(%2)\n"
-               "std    9,72(%2)\n"
-               "std    10,80(%2)\n"
-               "std    11,88(%2)\n"
-               "std    12,96(%2)\n"
-               "std    13,104(%2)\n"
-               "std    14,112(%2)\n"
-               "std    15,120(%2)\n"
-               "std    16,128(%2)\n"
-               "std    17,136(%2)\n"
-               "std    18,144(%2)\n"
-               "std    19,152(%2)\n"
-               "std    20,160(%2)\n"
-               "std    21,168(%2)\n"
-               "std    22,176(%2)\n"
-               "std    23,184(%2)\n"
-               "std    24,192(%2)\n"
-               "std    25,200(%2)\n"
-               "std    26,208(%2)\n"
-               "std    27,216(%2)\n"
-               "std    28,224(%2)\n"
-               "std    29,232(%2)\n"
-               "std    30,240(%2)\n"
-               "std    31,248(%2)\n"
-               "mfmsr  %0\n"
-               "std    %0, 264(%2)\n"
-               "mfctr  %0\n"
-               "std    %0, 280(%2)\n"
-               "mflr   %0\n"
-               "std    %0, 288(%2)\n"
-               "bl     1f\n"
-       "1:      mflr   %1\n"
-               "std    %1, 256(%2)\n"
-               "mtlr   %0\n"
-               "mfxer  %0\n"
-               "std    %0, 296(%2)\n"
-               : "=&r" (tmp1), "=&r" (tmp2)
-               : "b" (regs));
-}
-
-/* We may have saved_regs from where the error came from
- * or it is NULL if via a direct panic().
- */
-static void crash_save_self(struct pt_regs *saved_regs)
-{
-       struct pt_regs regs;
-       int cpu;
-
-       cpu = smp_processor_id();
-       if (saved_regs)
-               memcpy(&regs, saved_regs, sizeof(regs));
-       else
-               crash_get_current_regs(&regs);
-       crash_save_this_cpu(&regs, cpu);
-}
-
 #ifdef CONFIG_SMP
 static atomic_t waiting_for_crash_ipi;
 
@@ -260,5 +193,5 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
         */
        crashing_cpu = smp_processor_id();
        crash_kexec_prepare_cpus();
-       crash_save_self(regs);
+       crash_save_this_cpu(regs, crashing_cpu);
 }
index 036b71d2adfc191c0dd5e33be04264aae16894e0..d8da2a35c0a4adf62dd6b9cbe5d91f7470fc170e 100644 (file)
@@ -988,7 +988,7 @@ _GLOBAL(enter_rtas)
        stwu    r1,-INT_FRAME_SIZE(r1)
        mflr    r0
        stw     r0,INT_FRAME_SIZE+4(r1)
-       LOADADDR(r4, rtas)
+       LOAD_REG_ADDR(r4, rtas)
        lis     r6,1f@ha        /* physical return address for rtas */
        addi    r6,r6,1f@l
        tophys(r6,r6)
index aacebb33e98a1a9224371e943e5c9fb9f5163512..5420363188660db8803f4f771aca1ffb75481cbf 100644 (file)
@@ -511,7 +511,8 @@ restore:
        cmpdi   0,r5,0
        beq     4f
        /* Check for pending interrupts (iSeries) */
-       ld      r3,PACALPPACA+LPPACAANYINT(r13)
+       ld      r3,PACALPPACAPTR(r13)
+       ld      r3,LPPACAANYINT(r3)
        cmpdi   r3,0
        beq+    4f                      /* skip do_IRQ if no interrupts */
 
@@ -689,9 +690,8 @@ _GLOBAL(enter_rtas)
         std    r6,PACASAVEDMSR(r13)
 
        /* Setup our real return addr */        
-       SET_REG_TO_LABEL(r4,.rtas_return_loc)
-       SET_REG_TO_CONST(r9,PAGE_OFFSET)
-       sub     r4,r4,r9
+       LOAD_REG_ADDR(r4,.rtas_return_loc)
+       clrldi  r4,r4,2                 /* convert to realmode address */
                mtlr    r4
 
        li      r0,0
@@ -706,7 +706,7 @@ _GLOBAL(enter_rtas)
        sync                            /* disable interrupts so SRR0/1 */
        mtmsrd  r0                      /* don't get trashed */
 
-       SET_REG_TO_LABEL(r4,rtas)
+       LOAD_REG_ADDR(r4, rtas)
        ld      r5,RTASENTRY(r4)        /* get the rtas->entry value */
        ld      r4,RTASBASE(r4)         /* get the rtas->base value */
        
@@ -718,8 +718,7 @@ _GLOBAL(enter_rtas)
 _STATIC(rtas_return_loc)
        /* relocation is off at this point */
        mfspr   r4,SPRN_SPRG3           /* Get PACA */
-       SET_REG_TO_CONST(r5, PAGE_OFFSET)
-        sub     r4,r4,r5                /* RELOC the PACA base pointer */
+       clrldi  r4,r4,2                 /* convert to realmode address */
 
        mfmsr   r6
        li      r0,MSR_RI
@@ -728,7 +727,7 @@ _STATIC(rtas_return_loc)
        mtmsrd  r6
         
         ld     r1,PACAR1(r4)           /* Restore our SP */
-       LOADADDR(r3,.rtas_restore_regs)
+       LOAD_REG_IMMEDIATE(r3,.rtas_restore_regs)
         ld     r4,PACASAVEDMSR(r4)     /* Restore our MSR */
 
        mtspr   SPRN_SRR0,r3
index b780b42c95fc0f57c42dbb4b12ed58876742e4d3..e4362dfa37fba2e1971167c23d1a6c613152062e 100644 (file)
@@ -39,9 +39,9 @@ _GLOBAL(load_up_fpu)
  * to another.  Instead we call giveup_fpu in switch_to.
  */
 #ifndef CONFIG_SMP
-       LOADBASE(r3, last_task_used_math)
+       LOAD_REG_ADDRBASE(r3, last_task_used_math)
        toreal(r3)
-       PPC_LL  r4,OFF(last_task_used_math)(r3)
+       PPC_LL  r4,ADDROFF(last_task_used_math)(r3)
        PPC_LCMPI       0,r4,0
        beq     1f
        toreal(r4)
@@ -77,7 +77,7 @@ _GLOBAL(load_up_fpu)
 #ifndef CONFIG_SMP
        subi    r4,r5,THREAD
        fromreal(r4)
-       PPC_STL r4,OFF(last_task_used_math)(r3)
+       PPC_STL r4,ADDROFF(last_task_used_math)(r3)
 #endif /* CONFIG_SMP */
        /* restore registers and return */
        /* we haven't used ctr or xer or lr */
@@ -113,8 +113,8 @@ _GLOBAL(giveup_fpu)
 1:
 #ifndef CONFIG_SMP
        li      r5,0
-       LOADBASE(r4,last_task_used_math)
-       PPC_STL r5,OFF(last_task_used_math)(r4)
+       LOAD_REG_ADDRBASE(r4,last_task_used_math)
+       PPC_STL r5,ADDROFF(last_task_used_math)(r4)
 #endif /* CONFIG_SMP */
        blr
 
index 1c066d1253756ae3b9f008e5246bcbe2fa2bf9b3..3082684663428bffc0483a1995dc78b69cc3cc7d 100644 (file)
@@ -154,12 +154,12 @@ _GLOBAL(__secondary_hold)
        bne     100b
 
 #ifdef CONFIG_HMT
-       LOADADDR(r4, .hmt_init)
+       SET_REG_IMMEDIATE(r4, .hmt_init)
        mtctr   r4
        bctr
 #else
 #ifdef CONFIG_SMP
-       LOADADDR(r4, .pSeries_secondary_smp_init)
+       LOAD_REG_IMMEDIATE(r4, .pSeries_secondary_smp_init)
        mtctr   r4
        mr      r3,r24
        bctr
@@ -205,9 +205,10 @@ exception_marker:
 #define EX_LR          72
 
 /*
- * We're short on space and time in the exception prolog, so we can't use
- * the normal LOADADDR macro. Normally we just need the low halfword of the
- * address, but for Kdump we need the whole low word.
+ * We're short on space and time in the exception prolog, so we can't
+ * use the normal SET_REG_IMMEDIATE macro. Normally we just need the
+ * low halfword of the address, but for Kdump we need the whole low
+ * word.
  */
 #ifdef CONFIG_CRASH_DUMP
 #define LOAD_HANDLER(reg, label)                                       \
@@ -254,8 +255,9 @@ exception_marker:
 
 #define EXCEPTION_PROLOG_ISERIES_2                                     \
        mfmsr   r10;                                                    \
-       ld      r11,PACALPPACA+LPPACASRR0(r13);                         \
-       ld      r12,PACALPPACA+LPPACASRR1(r13);                         \
+       ld      r12,PACALPPACAPTR(r13);                                 \
+       ld      r11,LPPACASRR0(r12);                                    \
+       ld      r12,LPPACASRR1(r12);                                    \
        ori     r10,r10,MSR_RI;                                         \
        mtmsrd  r10,1
 
@@ -634,7 +636,8 @@ data_access_slb_iSeries:
        std     r12,PACA_EXSLB+EX_R12(r13)
        mfspr   r10,SPRN_SPRG1
        std     r10,PACA_EXSLB+EX_R13(r13)
-       ld      r12,PACALPPACA+LPPACASRR1(r13);
+       ld      r12,PACALPPACAPTR(r13)
+       ld      r12,LPPACASRR1(r12)
        b       .slb_miss_realmode
 
        STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN)
@@ -644,7 +647,8 @@ instruction_access_slb_iSeries:
        mtspr   SPRN_SPRG1,r13          /* save r13 */
        mfspr   r13,SPRN_SPRG3          /* get paca address into r13 */
        std     r3,PACA_EXSLB+EX_R3(r13)
-       ld      r3,PACALPPACA+LPPACASRR0(r13)   /* get SRR0 value */
+       ld      r3,PACALPPACAPTR(r13)
+       ld      r3,LPPACASRR0(r3)       /* get SRR0 value */
        std     r9,PACA_EXSLB+EX_R9(r13)
        mfcr    r9
 #ifdef __DISABLED__
@@ -656,7 +660,8 @@ instruction_access_slb_iSeries:
        std     r12,PACA_EXSLB+EX_R12(r13)
        mfspr   r10,SPRN_SPRG1
        std     r10,PACA_EXSLB+EX_R13(r13)
-       ld      r12,PACALPPACA+LPPACASRR1(r13);
+       ld      r12,PACALPPACAPTR(r13)
+       ld      r12,LPPACASRR1(r12)
        b       .slb_miss_realmode
 
 #ifdef __DISABLED__
@@ -713,7 +718,7 @@ system_reset_iSeries:
        lbz     r23,PACAPROCSTART(r13)  /* Test if this processor
                                         * should start */
        sync
-       LOADADDR(r3,current_set)
+       LOAD_REG_IMMEDIATE(r3,current_set)
        sldi    r28,r24,3               /* get current_set[cpu#] */
        ldx     r3,r3,r28
        addi    r1,r3,THREAD_SIZE
@@ -745,17 +750,19 @@ iSeries_secondary_smp_loop:
        .globl decrementer_iSeries_masked
 decrementer_iSeries_masked:
        li      r11,1
-       stb     r11,PACALPPACA+LPPACADECRINT(r13)
-       LOADBASE(r12,tb_ticks_per_jiffy)
-       lwz     r12,OFF(tb_ticks_per_jiffy)(r12)
+       ld      r12,PACALPPACAPTR(r13)
+       stb     r11,LPPACADECRINT(r12)
+       LOAD_REG_ADDRBASE(r12,tb_ticks_per_jiffy)
+       lwz     r12,ADDROFF(tb_ticks_per_jiffy)(r12)
        mtspr   SPRN_DEC,r12
        /* fall through */
 
        .globl hardware_interrupt_iSeries_masked
 hardware_interrupt_iSeries_masked:
        mtcrf   0x80,r9         /* Restore regs */
-       ld      r11,PACALPPACA+LPPACASRR0(r13)
-       ld      r12,PACALPPACA+LPPACASRR1(r13)
+       ld      r12,PACALPPACAPTR(r13)
+       ld      r11,LPPACASRR0(r12)
+       ld      r12,LPPACASRR1(r12)
        mtspr   SPRN_SRR0,r11
        mtspr   SPRN_SRR1,r12
        ld      r9,PACA_EXGEN+EX_R9(r13)
@@ -994,7 +1001,8 @@ _GLOBAL(slb_miss_realmode)
        ld      r3,PACA_EXSLB+EX_R3(r13)
        lwz     r9,PACA_EXSLB+EX_CCR(r13)       /* get saved CR */
 #ifdef CONFIG_PPC_ISERIES
-       ld      r11,PACALPPACA+LPPACASRR0(r13)  /* get SRR0 value */
+       ld      r11,PACALPPACAPTR(r13)
+       ld      r11,LPPACASRR0(r11)             /* get SRR0 value */
 #endif /* CONFIG_PPC_ISERIES */
 
        mtlr    r10
@@ -1412,7 +1420,7 @@ _GLOBAL(pSeries_secondary_smp_init)
         * physical cpu id in r24, we need to search the pacas to find
         * which logical id maps to our physical one.
         */
-       LOADADDR(r13, paca)             /* Get base vaddr of paca array  */
+       LOAD_REG_IMMEDIATE(r13, paca)   /* Get base vaddr of paca array  */
        li      r5,0                    /* logical cpu id                */
 1:     lhz     r6,PACAHWCPUID(r13)     /* Load HW procid from paca      */
        cmpw    r6,r24                  /* Compare to our id             */
@@ -1446,8 +1454,8 @@ _GLOBAL(pSeries_secondary_smp_init)
 #ifdef CONFIG_PPC_ISERIES
 _STATIC(__start_initialization_iSeries)
        /* Clear out the BSS */
-       LOADADDR(r11,__bss_stop)
-       LOADADDR(r8,__bss_start)
+       LOAD_REG_IMMEDIATE(r11,__bss_stop)
+       LOAD_REG_IMMEDIATE(r8,__bss_start)
        sub     r11,r11,r8              /* bss size                     */
        addi    r11,r11,7               /* round up to an even double word */
        rldicl. r11,r11,61,3            /* shift right by 3             */
@@ -1458,17 +1466,17 @@ _STATIC(__start_initialization_iSeries)
 3:     stdu    r0,8(r8)
        bdnz    3b
 4:
-       LOADADDR(r1,init_thread_union)
+       LOAD_REG_IMMEDIATE(r1,init_thread_union)
        addi    r1,r1,THREAD_SIZE
        li      r0,0
        stdu    r0,-STACK_FRAME_OVERHEAD(r1)
 
-       LOADADDR(r3,cpu_specs)
-       LOADADDR(r4,cur_cpu_spec)
+       LOAD_REG_IMMEDIATE(r3,cpu_specs)
+       LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
        li      r5,0
        bl      .identify_cpu
 
-       LOADADDR(r2,__toc_start)
+       LOAD_REG_IMMEDIATE(r2,__toc_start)
        addi    r2,r2,0x4000
        addi    r2,r2,0x4000
 
@@ -1528,7 +1536,7 @@ _GLOBAL(__start_initialization_multiplatform)
        li      r24,0
 
        /* Switch off MMU if not already */
-       LOADADDR(r4, .__after_prom_start - KERNELBASE)
+       LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
        add     r4,r4,r30
        bl      .__mmu_off
        b       .__after_prom_start
@@ -1548,7 +1556,7 @@ _STATIC(__boot_from_prom)
        /* put a relocation offset into r3 */
        bl      .reloc_offset
 
-       LOADADDR(r2,__toc_start)
+       LOAD_REG_IMMEDIATE(r2,__toc_start)
        addi    r2,r2,0x4000
        addi    r2,r2,0x4000
 
@@ -1588,9 +1596,9 @@ _STATIC(__after_prom_start)
  */
        bl      .reloc_offset
        mr      r26,r3
-       SET_REG_TO_CONST(r27,KERNELBASE)
+       LOAD_REG_IMMEDIATE(r27, KERNELBASE)
 
-       LOADADDR(r3, PHYSICAL_START)    /* target addr */
+       LOAD_REG_IMMEDIATE(r3, PHYSICAL_START)  /* target addr */
 
        // XXX FIXME: Use phys returned by OF (r30)
        add     r4,r27,r26              /* source addr                   */
@@ -1598,7 +1606,7 @@ _STATIC(__after_prom_start)
                                        /*   i.e. where we are running   */
                                        /*      the source addr          */
 
-       LOADADDR(r5,copy_to_here)       /* # bytes of memory to copy     */
+       LOAD_REG_IMMEDIATE(r5,copy_to_here) /* # bytes of memory to copy */
        sub     r5,r5,r27
 
        li      r6,0x100                /* Start offset, the first 0x100 */
@@ -1608,11 +1616,11 @@ _STATIC(__after_prom_start)
                                        /* this includes the code being  */
                                        /* executed here.                */
 
-       LOADADDR(r0, 4f)                /* Jump to the copy of this code */
+       LOAD_REG_IMMEDIATE(r0, 4f)      /* Jump to the copy of this code */
        mtctr   r0                      /* that we just made/relocated   */
        bctr
 
-4:     LOADADDR(r5,klimit)
+4:     LOAD_REG_IMMEDIATE(r5,klimit)
        add     r5,r5,r26
        ld      r5,0(r5)                /* get the value of klimit */
        sub     r5,r5,r27
@@ -1694,7 +1702,7 @@ _GLOBAL(pmac_secondary_start)
        mtmsrd  r3                      /* RI on */
 
        /* Set up a paca value for this processor. */
-       LOADADDR(r4, paca)               /* Get base vaddr of paca array        */
+       LOAD_REG_IMMEDIATE(r4, paca)    /* Get base vaddr of paca array */
        mulli   r13,r24,PACA_SIZE        /* Calculate vaddr of right paca */
        add     r13,r13,r4              /* for this processor.          */
        mtspr   SPRN_SPRG3,r13           /* Save vaddr of paca in SPRG3 */
@@ -1731,7 +1739,7 @@ _GLOBAL(__secondary_start)
        bl      .early_setup_secondary
 
        /* Initialize the kernel stack.  Just a repeat for iSeries.      */
-       LOADADDR(r3,current_set)
+       LOAD_REG_ADDR(r3, current_set)
        sldi    r28,r24,3               /* get current_set[cpu#]         */
        ldx     r1,r3,r28
        addi    r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
@@ -1742,8 +1750,8 @@ _GLOBAL(__secondary_start)
        mtlr    r7
 
        /* enable MMU and jump to start_secondary */
-       LOADADDR(r3,.start_secondary_prolog)
-       SET_REG_TO_CONST(r4, MSR_KERNEL)
+       LOAD_REG_ADDR(r3, .start_secondary_prolog)
+       LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
 #ifdef DO_SOFT_DISABLE
        ori     r4,r4,MSR_EE
 #endif
@@ -1792,8 +1800,8 @@ _STATIC(start_here_multiplatform)
         * be detached from the kernel completely. Besides, we need
         * to clear it now for kexec-style entry.
         */
-       LOADADDR(r11,__bss_stop)
-       LOADADDR(r8,__bss_start)
+       LOAD_REG_IMMEDIATE(r11,__bss_stop)
+       LOAD_REG_IMMEDIATE(r8,__bss_start)
        sub     r11,r11,r8              /* bss size                     */
        addi    r11,r11,7               /* round up to an even double word */
        rldicl. r11,r11,61,3            /* shift right by 3             */
@@ -1831,7 +1839,7 @@ _STATIC(start_here_multiplatform)
        /* up the htab.  This is done because we have relocated the  */
        /* kernel but are still running in real mode. */
 
-       LOADADDR(r3,init_thread_union)
+       LOAD_REG_IMMEDIATE(r3,init_thread_union)
        add     r3,r3,r26
 
        /* set up a stack pointer (physical address) */
@@ -1840,14 +1848,14 @@ _STATIC(start_here_multiplatform)
        stdu    r0,-STACK_FRAME_OVERHEAD(r1)
 
        /* set up the TOC (physical address) */
-       LOADADDR(r2,__toc_start)
+       LOAD_REG_IMMEDIATE(r2,__toc_start)
        addi    r2,r2,0x4000
        addi    r2,r2,0x4000
        add     r2,r2,r26
 
-       LOADADDR(r3,cpu_specs)
+       LOAD_REG_IMMEDIATE(r3, cpu_specs)
        add     r3,r3,r26
-       LOADADDR(r4,cur_cpu_spec)
+       LOAD_REG_IMMEDIATE(r4,cur_cpu_spec)
        add     r4,r4,r26
        mr      r5,r26
        bl      .identify_cpu
@@ -1863,11 +1871,11 @@ _STATIC(start_here_multiplatform)
         * nowhere it can be initialized differently before we reach this
         * code
         */
-       LOADADDR(r27, boot_cpuid)
+       LOAD_REG_IMMEDIATE(r27, boot_cpuid)
        add     r27,r27,r26
        lwz     r27,0(r27)
 
-       LOADADDR(r24, paca)             /* Get base vaddr of paca array  */
+       LOAD_REG_IMMEDIATE(r24, paca)   /* Get base vaddr of paca array  */
        mulli   r13,r27,PACA_SIZE       /* Calculate vaddr of right paca */
        add     r13,r13,r24             /* for this processor.           */
        add     r13,r13,r26             /* convert to physical addr      */
@@ -1880,8 +1888,8 @@ _STATIC(start_here_multiplatform)
        mr      r3,r31
        bl      .early_setup
 
-       LOADADDR(r3,.start_here_common)
-       SET_REG_TO_CONST(r4, MSR_KERNEL)
+       LOAD_REG_IMMEDIATE(r3, .start_here_common)
+       LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
        mtspr   SPRN_SRR0,r3
        mtspr   SPRN_SRR1,r4
        rfid
@@ -1895,7 +1903,7 @@ _STATIC(start_here_common)
        /* The following code sets up the SP and TOC now that we are */
        /* running with translation enabled. */
 
-       LOADADDR(r3,init_thread_union)
+       LOAD_REG_IMMEDIATE(r3,init_thread_union)
 
        /* set up the stack */
        addi    r1,r3,THREAD_SIZE
@@ -1908,16 +1916,16 @@ _STATIC(start_here_common)
        li      r3,0
        bl      .do_cpu_ftr_fixups
 
-       LOADADDR(r26, boot_cpuid)
+       LOAD_REG_IMMEDIATE(r26, boot_cpuid)
        lwz     r26,0(r26)
 
-       LOADADDR(r24, paca)             /* Get base vaddr of paca array  */
+       LOAD_REG_IMMEDIATE(r24, paca)   /* Get base vaddr of paca array  */
        mulli   r13,r26,PACA_SIZE       /* Calculate vaddr of right paca */
        add     r13,r13,r24             /* for this processor.           */
        mtspr   SPRN_SPRG3,r13
 
        /* ptr to current */
-       LOADADDR(r4,init_task)
+       LOAD_REG_IMMEDIATE(r4, init_task)
        std     r4,PACACURRENT(r13)
 
        /* Load the TOC */
@@ -1940,7 +1948,7 @@ _STATIC(start_here_common)
 
 _GLOBAL(hmt_init)
 #ifdef CONFIG_HMT
-       LOADADDR(r5, hmt_thread_data)
+       LOAD_REG_IMMEDIATE(r5, hmt_thread_data)
        mfspr   r7,SPRN_PVR
        srwi    r7,r7,16
        cmpwi   r7,0x34                 /* Pulsar  */
@@ -1961,7 +1969,7 @@ _GLOBAL(hmt_init)
        b       101f
 
 __hmt_secondary_hold:
-       LOADADDR(r5, hmt_thread_data)
+       LOAD_REG_IMMEDIATE(r5, hmt_thread_data)
        clrldi  r5,r5,4
        li      r7,0
        mfspr   r6,SPRN_PIR
@@ -1989,7 +1997,7 @@ __hmt_secondary_hold:
 
 #ifdef CONFIG_HMT
 _GLOBAL(hmt_start_secondary)
-       LOADADDR(r4,__hmt_secondary_hold)
+       LOAD_REG_IMMEDIATE(r4,__hmt_secondary_hold)
        clrldi  r4,r4,4
        mtspr   SPRN_NIADORM, r4
        mfspr   r4, SPRN_MSRDORM
index 1494e2f177f7e3baa04314d68b327b15d5272dae..c16b4afab582f4ed3e4306045a0b4995d4e1d636 100644 (file)
@@ -38,14 +38,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
        /* We must dynamically check for the NAP feature as it
         * can be cleared by CPU init after the fixups are done
         */
-       LOADBASE(r3,cur_cpu_spec)
-       ld      r4,OFF(cur_cpu_spec)(r3)
+       LOAD_REG_ADDRBASE(r3,cur_cpu_spec)
+       ld      r4,ADDROFF(cur_cpu_spec)(r3)
        ld      r4,CPU_SPEC_FEATURES(r4)
        andi.   r0,r4,CPU_FTR_CAN_NAP
        beqlr
        /* Now check if user or arch enabled NAP mode */
-       LOADBASE(r3,powersave_nap)
-       lwz     r4,OFF(powersave_nap)(r3)
+       LOAD_REG_ADDRBASE(r3,powersave_nap)
+       lwz     r4,ADDROFF(powersave_nap)(r3)
        cmpwi   0,r4,0
        beqlr
 
index 5651032d870620d7a72eaeea7dca93ef5790c251..d1fffce86df920799cad33996d51035b0bc3ebe0 100644 (file)
@@ -238,14 +238,10 @@ void do_IRQ(struct pt_regs *regs)
         irq_exit();
 
 #ifdef CONFIG_PPC_ISERIES
-       {
-               struct paca_struct *lpaca = get_paca();
-
-               if (lpaca->lppaca.int_dword.fields.decr_int) {
-                       lpaca->lppaca.int_dword.fields.decr_int = 0;
-                       /* Signal a fake decrementer interrupt */
-                       timer_interrupt(regs);
-               }
+       if (get_lppaca()->int_dword.fields.decr_int) {
+               get_lppaca()->int_dword.fields.decr_int = 0;
+               /* Signal a fake decrementer interrupt */
+               timer_interrupt(regs);
        }
 #endif
 }
index 9dda16ccde78600f0444f0db8a9579fed4397e41..1ae96a8ed7e21f080327d71764589ec00feeaf2b 100644 (file)
@@ -55,15 +55,13 @@ static unsigned long get_purr(void)
 {
        unsigned long sum_purr = 0;
        int cpu;
-       struct paca_struct *lpaca;
 
        for_each_cpu(cpu) {
-               lpaca = paca + cpu;
-               sum_purr += lpaca->lppaca.emulated_time_base;
+               sum_purr += lppaca[cpu].emulated_time_base;
 
 #ifdef PURR_DEBUG
                printk(KERN_INFO "get_purr for cpu (%d) has value (%ld) \n",
-                       cpu, lpaca->lppaca.emulated_time_base);
+                       cpu, lppaca[cpu].emulated_time_base);
 #endif
        }
        return sum_purr;
@@ -79,12 +77,11 @@ static int lparcfg_data(struct seq_file *m, void *v)
        unsigned long pool_id, lp_index;
        int shared, entitled_capacity, max_entitled_capacity;
        int processors, max_processors;
-       struct paca_struct *lpaca = get_paca();
        unsigned long purr = get_purr();
 
        seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
 
-       shared = (int)(lpaca->lppaca_ptr->shared_proc);
+       shared = (int)(get_lppaca()->shared_proc);
        seq_printf(m, "serial_number=%c%c%c%c%c%c%c\n",
                   e2a(xItExtVpdPanel.mfgID[2]),
                   e2a(xItExtVpdPanel.mfgID[3]),
@@ -402,7 +399,7 @@ static int lparcfg_data(struct seq_file *m, void *v)
                           (h_resource >> 0 * 8) & 0xffff);
 
                /* pool related entries are apropriate for shared configs */
-               if (paca[0].lppaca.shared_proc) {
+               if (lppaca[0].shared_proc) {
 
                        h_pic(&pool_idle_time, &pool_procs);
 
@@ -451,7 +448,7 @@ static int lparcfg_data(struct seq_file *m, void *v)
        seq_printf(m, "partition_potential_processors=%d\n",
                   partition_potential_processors);
 
-       seq_printf(m, "shared_processor_mode=%d\n", paca[0].lppaca.shared_proc);
+       seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
 
        return 0;
 }
index 01d0d97a16e1e657363e2410de6a3f9918c31a5a..be982023409ec2179833ebceefd4a6ff02aa32c7 100644 (file)
@@ -68,7 +68,7 @@ _GLOBAL(reloc_offset)
        mflr    r0
        bl      1f
 1:     mflr    r3
-       LOADADDR(r4,1b)
+       LOAD_REG_IMMEDIATE(r4,1b)
        subf    r3,r4,r3
        mtlr    r0
        blr
@@ -80,7 +80,7 @@ _GLOBAL(add_reloc_offset)
        mflr    r0
        bl      1f
 1:     mflr    r5
-       LOADADDR(r4,1b)
+       LOAD_REG_IMMEDIATE(r4,1b)
        subf    r5,r4,r5
        add     r3,r3,r5
        mtlr    r0
index ae48a002f81ad1bf94f54b411b7d1e27356a44d2..2778cce058e2af29ff7d66152dfd59d4d7d62fe4 100644 (file)
@@ -39,7 +39,7 @@ _GLOBAL(reloc_offset)
        mflr    r0
        bl      1f
 1:     mflr    r3
-       LOADADDR(r4,1b)
+       LOAD_REG_IMMEDIATE(r4,1b)
        subf    r3,r4,r3
        mtlr    r0
        blr
@@ -51,7 +51,7 @@ _GLOBAL(add_reloc_offset)
        mflr    r0
        bl      1f
 1:     mflr    r5
-       LOADADDR(r4,1b)
+       LOAD_REG_IMMEDIATE(r4,1b)
        subf    r5,r4,r5
        add     r3,r3,r5
        mtlr    r0
@@ -498,15 +498,15 @@ _GLOBAL(identify_cpu)
  */
 _GLOBAL(do_cpu_ftr_fixups)
        /* Get CPU 0 features */
-       LOADADDR(r6,cur_cpu_spec)
+       LOAD_REG_IMMEDIATE(r6,cur_cpu_spec)
        sub     r6,r6,r3
        ld      r4,0(r6)
        sub     r4,r4,r3
        ld      r4,CPU_SPEC_FEATURES(r4)
        /* Get the fixup table */
-       LOADADDR(r6,__start___ftr_fixup)
+       LOAD_REG_IMMEDIATE(r6,__start___ftr_fixup)
        sub     r6,r6,r3
-       LOADADDR(r7,__stop___ftr_fixup)
+       LOAD_REG_IMMEDIATE(r7,__stop___ftr_fixup)
        sub     r7,r7,r3
        /* Do the fixup */
 1:     cmpld   r6,r7
index 7065e40e2f42ac8661fb372c371911aa17c76a23..22d83d4d1af5f6ce33d3ba0b9cce8b26ed30b1e8 100644 (file)
@@ -132,6 +132,8 @@ static int of_device_resume(struct device * dev)
 struct bus_type of_platform_bus_type = {
        .name   = "of_platform",
        .match  = of_platform_bus_match,
+       .probe  = of_device_probe,
+       .remove = of_device_remove,
        .suspend        = of_device_suspend,
        .resume = of_device_resume,
 };
@@ -150,8 +152,6 @@ int of_register_driver(struct of_platform_driver *drv)
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &of_platform_bus_type;
-       drv->driver.probe = of_device_probe;
-       drv->driver.remove = of_device_remove;
 
        /* register with core */
        count = driver_register(&drv->driver);
index 999bdd816769ba1f63fbf332f2dc0e224630a410..5d1b708086bd33d9a9a26472fbdfedccfd93e6d1 100644 (file)
  * field correctly */
 extern unsigned long __toc_start;
 
+/*
+ * iSeries structure which the hypervisor knows about - this structure
+ * should not cross a page boundary.  The vpa_init/register_vpa call
+ * is now known to fail if the lppaca structure crosses a page
+ * boundary.  The lppaca is also used on POWER5 pSeries boxes.  The
+ * lppaca is 640 bytes long, and cannot readily change since the
+ * hypervisor knows its layout, so a 1kB alignment will suffice to
+ * ensure that it doesn't cross a page boundary.
+ */
+struct lppaca lppaca[] = {
+       [0 ... (NR_CPUS-1)] = {
+               .desc = 0xd397d781,     /* "LpPa" */
+               .size = sizeof(struct lppaca),
+               .dyn_proc_status = 2,
+               .decr_val = 0x00ff0000,
+               .fpregs_in_use = 1,
+               .end_of_quantum = 0xfffffffffffffffful,
+               .slb_count = 64,
+               .vmxregs_in_use = 0,
+       },
+};
+
 /* The Paca is an array with one entry per processor.  Each contains an
  * lppaca, which contains the information shared between the
  * hypervisor and Linux.
@@ -35,27 +57,17 @@ extern unsigned long __toc_start;
  * processor (not thread).
  */
 #define PACA_INIT_COMMON(number, start, asrr, asrv)                        \
+       .lppaca_ptr = &lppaca[number],                                      \
        .lock_token = 0x8000,                                               \
        .paca_index = (number),         /* Paca Index */                    \
        .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL,             \
        .stab_real = (asrr),            /* Real pointer to segment table */ \
        .stab_addr = (asrv),            /* Virt pointer to segment table */ \
        .cpu_start = (start),           /* Processor start */               \
-       .hw_cpu_id = 0xffff,                                                \
-       .lppaca = {                                                         \
-               .desc = 0xd397d781,     /* "LpPa" */                        \
-               .size = sizeof(struct lppaca),                              \
-               .dyn_proc_status = 2,                                       \
-               .decr_val = 0x00ff0000,                                     \
-               .fpregs_in_use = 1,                                         \
-               .end_of_quantum = 0xfffffffffffffffful,                     \
-               .slb_count = 64,                                            \
-               .vmxregs_in_use = 0,                                        \
-       },                                                                  \
+       .hw_cpu_id = 0xffff,
 
 #ifdef CONFIG_PPC_ISERIES
 #define PACA_INIT_ISERIES(number)                                          \
-       .lppaca_ptr = &paca[number].lppaca,                                 \
        .reg_save_ptr = &iseries_reg_save[number],
 
 #define PACA_INIT(number)                                                  \
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
new file mode 100644 (file)
index 0000000..704c846
--- /dev/null
@@ -0,0 +1,1897 @@
+/*
+ * Common pmac/prep/chrp pci routines. -- Cort
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/pci-bridge.h>
+#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+unsigned long isa_io_base     = 0;
+unsigned long isa_mem_base    = 0;
+unsigned long pci_dram_offset = 0;
+int pcibios_assign_bus_offset = 1;
+
+void pcibios_make_OF_bus_map(void);
+
+static int pci_relocate_bridge_resource(struct pci_bus *bus, int i);
+static int probe_resource(struct pci_bus *parent, struct resource *pr,
+                         struct resource *res, struct resource **conflict);
+static void update_bridge_base(struct pci_bus *bus, int i);
+static void pcibios_fixup_resources(struct pci_dev* dev);
+static void fixup_broken_pcnet32(struct pci_dev* dev);
+static int reparent_resources(struct resource *parent, struct resource *res);
+static void fixup_cpc710_pci64(struct pci_dev* dev);
+#ifdef CONFIG_PPC_OF
+static u8* pci_to_OF_bus_map;
+#endif
+
+/* By default, we don't re-assign bus numbers. We do this only on
+ * some pmacs
+ */
+int pci_assign_all_buses;
+
+struct pci_controller* hose_head;
+struct pci_controller** hose_tail = &hose_head;
+
+static int pci_bus_count;
+
+static void
+fixup_broken_pcnet32(struct pci_dev* dev)
+{
+       if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
+               dev->vendor = PCI_VENDOR_ID_AMD;
+               pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT,        PCI_ANY_ID,                     fixup_broken_pcnet32);
+
+static void
+fixup_cpc710_pci64(struct pci_dev* dev)
+{
+       /* Hide the PCI64 BARs from the kernel as their content doesn't
+        * fit well in the resource management
+        */
+       dev->resource[0].start = dev->resource[0].end = 0;
+       dev->resource[0].flags = 0;
+       dev->resource[1].start = dev->resource[1].end = 0;
+       dev->resource[1].flags = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM,    PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64);
+
+static void
+pcibios_fixup_resources(struct pci_dev *dev)
+{
+       struct pci_controller* hose = (struct pci_controller *)dev->sysdata;
+       int i;
+       unsigned long offset;
+
+       if (!hose) {
+               printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev));
+               return;
+       }
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               struct resource *res = dev->resource + i;
+               if (!res->flags)
+                       continue;
+               if (res->end == 0xffffffff) {
+                       DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
+                           pci_name(dev), i, res->start, res->end);
+                       res->end -= res->start;
+                       res->start = 0;
+                       res->flags |= IORESOURCE_UNSET;
+                       continue;
+               }
+               offset = 0;
+               if (res->flags & IORESOURCE_MEM) {
+                       offset = hose->pci_mem_offset;
+               } else if (res->flags & IORESOURCE_IO) {
+                       offset = (unsigned long) hose->io_base_virt
+                               - isa_io_base;
+               }
+               if (offset != 0) {
+                       res->start += offset;
+                       res->end += offset;
+#ifdef DEBUG
+                       printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n",
+                              i, res->flags, pci_name(dev),
+                              res->start - offset, res->start);
+#endif
+               }
+       }
+
+       /* Call machine specific resource fixup */
+       if (ppc_md.pcibios_fixup_resources)
+               ppc_md.pcibios_fixup_resources(dev);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,           PCI_ANY_ID,                     pcibios_fixup_resources);
+
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+                       struct resource *res)
+{
+       unsigned long offset = 0;
+       struct pci_controller *hose = dev->sysdata;
+
+       if (hose && res->flags & IORESOURCE_IO)
+               offset = (unsigned long)hose->io_base_virt - isa_io_base;
+       else if (hose && res->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+       region->start = res->start - offset;
+       region->end = res->end - offset;
+}
+EXPORT_SYMBOL(pcibios_resource_to_bus);
+
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+                            struct pci_bus_region *region)
+{
+       unsigned long offset = 0;
+       struct pci_controller *hose = dev->sysdata;
+
+       if (hose && res->flags & IORESOURCE_IO)
+               offset = (unsigned long)hose->io_base_virt - isa_io_base;
+       else if (hose && res->flags & IORESOURCE_MEM)
+               offset = hose->pci_mem_offset;
+       res->start = region->start + offset;
+       res->end = region->end + offset;
+}
+EXPORT_SYMBOL(pcibios_bus_to_resource);
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+                      unsigned long align)
+{
+       struct pci_dev *dev = data;
+
+       if (res->flags & IORESOURCE_IO) {
+               unsigned long start = res->start;
+
+               if (size > 0x100) {
+                       printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+                              " (%ld bytes)\n", pci_name(dev),
+                              dev->resource - res, size);
+               }
+
+               if (start & 0x300) {
+                       start = (start + 0x3ff) & ~0x3ff;
+                       res->start = start;
+               }
+       }
+}
+EXPORT_SYMBOL(pcibios_align_resource);
+
+/*
+ *  Handle resources of PCI devices.  If the world were perfect, we could
+ *  just allocate all the resource regions and do nothing more.  It isn't.
+ *  On the other hand, we cannot just re-allocate all devices, as it would
+ *  require us to know lots of host bridge internals.  So we attempt to
+ *  keep as much of the original configuration as possible, but tweak it
+ *  when it's found to be wrong.
+ *
+ *  Known BIOS problems we have to work around:
+ *     - I/O or memory regions not configured
+ *     - regions configured, but not enabled in the command register
+ *     - bogus I/O addresses above 64K used
+ *     - expansion ROMs left enabled (this may sound harmless, but given
+ *       the fact the PCI specs explicitly allow address decoders to be
+ *       shared between expansion ROMs and other resource regions, it's
+ *       at least dangerous)
+ *
+ *  Our solution:
+ *     (1) Allocate resources for all buses behind PCI-to-PCI bridges.
+ *         This gives us fixed barriers on where we can allocate.
+ *     (2) Allocate resources for all enabled devices.  If there is
+ *         a collision, just mark the resource as unallocated. Also
+ *         disable expansion ROMs during this step.
+ *     (3) Try to allocate resources for disabled devices.  If the
+ *         resources were assigned correctly, everything goes well,
+ *         if they weren't, they won't disturb allocation of other
+ *         resources.
+ *     (4) Assign new addresses to resources which were either
+ *         not configured at all or misconfigured.  If explicitly
+ *         requested by the user, configure expansion ROM address
+ *         as well.
+ */
+
+static void __init
+pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+       struct pci_bus *bus;
+       int i;
+       struct resource *res, *pr;
+
+       /* Depth-First Search on bus tree */
+       list_for_each_entry(bus, bus_list, node) {
+               for (i = 0; i < 4; ++i) {
+                       if ((res = bus->resource[i]) == NULL || !res->flags
+                           || res->start > res->end)
+                               continue;
+                       if (bus->parent == NULL)
+                               pr = (res->flags & IORESOURCE_IO)?
+                                       &ioport_resource: &iomem_resource;
+                       else {
+                               pr = pci_find_parent_resource(bus->self, res);
+                               if (pr == res) {
+                                       /* this happens when the generic PCI
+                                        * code (wrongly) decides that this
+                                        * bridge is transparent  -- paulus
+                                        */
+                                       continue;
+                               }
+                       }
+
+                       DBG("PCI: bridge rsrc %lx..%lx (%lx), parent %p\n",
+                           res->start, res->end, res->flags, pr);
+                       if (pr) {
+                               if (request_resource(pr, res) == 0)
+                                       continue;
+                               /*
+                                * Must be a conflict with an existing entry.
+                                * Move that entry (or entries) under the
+                                * bridge resource and try again.
+                                */
+                               if (reparent_resources(pr, res) == 0)
+                                       continue;
+                       }
+                       printk(KERN_ERR "PCI: Cannot allocate resource region "
+                              "%d of PCI bridge %d\n", i, bus->number);
+                       if (pci_relocate_bridge_resource(bus, i))
+                               bus->resource[i] = NULL;
+               }
+               pcibios_allocate_bus_resources(&bus->children);
+       }
+}
+
+/*
+ * Reparent resource children of pr that conflict with res
+ * under res, and make res replace those children.
+ */
+static int __init
+reparent_resources(struct resource *parent, struct resource *res)
+{
+       struct resource *p, **pp;
+       struct resource **firstpp = NULL;
+
+       for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) {
+               if (p->end < res->start)
+                       continue;
+               if (res->end < p->start)
+                       break;
+               if (p->start < res->start || p->end > res->end)
+                       return -1;      /* not completely contained */
+               if (firstpp == NULL)
+                       firstpp = pp;
+       }
+       if (firstpp == NULL)
+               return -1;      /* didn't find any conflicting entries? */
+       res->parent = parent;
+       res->child = *firstpp;
+       res->sibling = *pp;
+       *firstpp = res;
+       *pp = NULL;
+       for (p = res->child; p != NULL; p = p->sibling) {
+               p->parent = res;
+               DBG(KERN_INFO "PCI: reparented %s [%lx..%lx] under %s\n",
+                   p->name, p->start, p->end, res->name);
+       }
+       return 0;
+}
+
+/*
+ * A bridge has been allocated a range which is outside the range
+ * of its parent bridge, so it needs to be moved.
+ */
+static int __init
+pci_relocate_bridge_resource(struct pci_bus *bus, int i)
+{
+       struct resource *res, *pr, *conflict;
+       unsigned long try, size;
+       int j;
+       struct pci_bus *parent = bus->parent;
+
+       if (parent == NULL) {
+               /* shouldn't ever happen */
+               printk(KERN_ERR "PCI: can't move host bridge resource\n");
+               return -1;
+       }
+       res = bus->resource[i];
+       if (res == NULL)
+               return -1;
+       pr = NULL;
+       for (j = 0; j < 4; j++) {
+               struct resource *r = parent->resource[j];
+               if (!r)
+                       continue;
+               if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
+                       continue;
+               if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) {
+                       pr = r;
+                       break;
+               }
+               if (res->flags & IORESOURCE_PREFETCH)
+                       pr = r;
+       }
+       if (pr == NULL)
+               return -1;
+       size = res->end - res->start;
+       if (pr->start > pr->end || size > pr->end - pr->start)
+               return -1;
+       try = pr->end;
+       for (;;) {
+               res->start = try - size;
+               res->end = try;
+               if (probe_resource(bus->parent, pr, res, &conflict) == 0)
+                       break;
+               if (conflict->start <= pr->start + size)
+                       return -1;
+               try = conflict->start - 1;
+       }
+       if (request_resource(pr, res)) {
+               DBG(KERN_ERR "PCI: huh? couldn't move to %lx..%lx\n",
+                   res->start, res->end);
+               return -1;              /* "can't happen" */
+       }
+       update_bridge_base(bus, i);
+       printk(KERN_INFO "PCI: bridge %d resource %d moved to %lx..%lx\n",
+              bus->number, i, res->start, res->end);
+       return 0;
+}
+
+static int __init
+probe_resource(struct pci_bus *parent, struct resource *pr,
+              struct resource *res, struct resource **conflict)
+{
+       struct pci_bus *bus;
+       struct pci_dev *dev;
+       struct resource *r;
+       int i;
+
+       for (r = pr->child; r != NULL; r = r->sibling) {
+               if (r->end >= res->start && res->end >= r->start) {
+                       *conflict = r;
+                       return 1;
+               }
+       }
+       list_for_each_entry(bus, &parent->children, node) {
+               for (i = 0; i < 4; ++i) {
+                       if ((r = bus->resource[i]) == NULL)
+                               continue;
+                       if (!r->flags || r->start > r->end || r == res)
+                               continue;
+                       if (pci_find_parent_resource(bus->self, r) != pr)
+                               continue;
+                       if (r->end >= res->start && res->end >= r->start) {
+                               *conflict = r;
+                               return 1;
+                       }
+               }
+       }
+       list_for_each_entry(dev, &parent->devices, bus_list) {
+               for (i = 0; i < 6; ++i) {
+                       r = &dev->resource[i];
+                       if (!r->flags || (r->flags & IORESOURCE_UNSET))
+                               continue;
+                       if (pci_find_parent_resource(dev, r) != pr)
+                               continue;
+                       if (r->end >= res->start && res->end >= r->start) {
+                               *conflict = r;
+                               return 1;
+                       }
+               }
+       }
+       return 0;
+}
+
+static void __init
+update_bridge_base(struct pci_bus *bus, int i)
+{
+       struct resource *res = bus->resource[i];
+       u8 io_base_lo, io_limit_lo;
+       u16 mem_base, mem_limit;
+       u16 cmd;
+       unsigned long start, end, off;
+       struct pci_dev *dev = bus->self;
+       struct pci_controller *hose = dev->sysdata;
+
+       if (!hose) {
+               printk("update_bridge_base: no hose?\n");
+               return;
+       }
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_write_config_word(dev, PCI_COMMAND,
+                             cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+       if (res->flags & IORESOURCE_IO) {
+               off = (unsigned long) hose->io_base_virt - isa_io_base;
+               start = res->start - off;
+               end = res->end - off;
+               io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK;
+               io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK;
+               if (end > 0xffff) {
+                       pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
+                                             start >> 16);
+                       pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
+                                             end >> 16);
+                       io_base_lo |= PCI_IO_RANGE_TYPE_32;
+               } else
+                       io_base_lo |= PCI_IO_RANGE_TYPE_16;
+               pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo);
+               pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo);
+
+       } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+                  == IORESOURCE_MEM) {
+               off = hose->pci_mem_offset;
+               mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK;
+               mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK;
+               pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base);
+               pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit);
+
+       } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+                  == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) {
+               off = hose->pci_mem_offset;
+               mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK;
+               mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK;
+               pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base);
+               pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit);
+
+       } else {
+               DBG(KERN_ERR "PCI: ugh, bridge %s res %d has flags=%lx\n",
+                   pci_name(dev), i, res->flags);
+       }
+       pci_write_config_word(dev, PCI_COMMAND, cmd);
+}
+
+static inline void alloc_resource(struct pci_dev *dev, int idx)
+{
+       struct resource *pr, *r = &dev->resource[idx];
+
+       DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n",
+           pci_name(dev), idx, r->start, r->end, r->flags);
+       pr = pci_find_parent_resource(dev, r);
+       if (!pr || request_resource(pr, r) < 0) {
+               printk(KERN_ERR "PCI: Cannot allocate resource region %d"
+                      " of device %s\n", idx, pci_name(dev));
+               if (pr)
+                       DBG("PCI:  parent is %p: %08lx-%08lx (f=%lx)\n",
+                           pr, pr->start, pr->end, pr->flags);
+               /* We'll assign a new address later */
+               r->flags |= IORESOURCE_UNSET;
+               r->end -= r->start;
+               r->start = 0;
+       }
+}
+
+static void __init
+pcibios_allocate_resources(int pass)
+{
+       struct pci_dev *dev = NULL;
+       int idx, disabled;
+       u16 command;
+       struct resource *r;
+
+       for_each_pci_dev(dev) {
+               pci_read_config_word(dev, PCI_COMMAND, &command);
+               for (idx = 0; idx < 6; idx++) {
+                       r = &dev->resource[idx];
+                       if (r->parent)          /* Already allocated */
+                               continue;
+                       if (!r->flags || (r->flags & IORESOURCE_UNSET))
+                               continue;       /* Not assigned at all */
+                       if (r->flags & IORESOURCE_IO)
+                               disabled = !(command & PCI_COMMAND_IO);
+                       else
+                               disabled = !(command & PCI_COMMAND_MEMORY);
+                       if (pass == disabled)
+                               alloc_resource(dev, idx);
+               }
+               if (pass)
+                       continue;
+               r = &dev->resource[PCI_ROM_RESOURCE];
+               if (r->flags & IORESOURCE_ROM_ENABLE) {
+                       /* Turn the ROM off, leave the resource region, but keep it unregistered. */
+                       u32 reg;
+                       DBG("PCI: Switching off ROM of %s\n", pci_name(dev));
+                       r->flags &= ~IORESOURCE_ROM_ENABLE;
+                       pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+                       pci_write_config_dword(dev, dev->rom_base_reg,
+                                              reg & ~PCI_ROM_ADDRESS_ENABLE);
+               }
+       }
+}
+
+static void __init
+pcibios_assign_resources(void)
+{
+       struct pci_dev *dev = NULL;
+       int idx;
+       struct resource *r;
+
+       for_each_pci_dev(dev) {
+               int class = dev->class >> 8;
+
+               /* Don't touch classless devices and host bridges */
+               if (!class || class == PCI_CLASS_BRIDGE_HOST)
+                       continue;
+
+               for (idx = 0; idx < 6; idx++) {
+                       r = &dev->resource[idx];
+
+                       /*
+                        * We shall assign a new address to this resource,
+                        * either because the BIOS (sic) forgot to do so
+                        * or because we have decided the old address was
+                        * unusable for some reason.
+                        */
+                       if ((r->flags & IORESOURCE_UNSET) && r->end &&
+                           (!ppc_md.pcibios_enable_device_hook ||
+                            !ppc_md.pcibios_enable_device_hook(dev, 1))) {
+                               r->flags &= ~IORESOURCE_UNSET;
+                               pci_assign_resource(dev, idx);
+                       }
+               }
+
+#if 0 /* don't assign ROMs */
+               r = &dev->resource[PCI_ROM_RESOURCE];
+               r->end -= r->start;
+               r->start = 0;
+               if (r->end)
+                       pci_assign_resource(dev, PCI_ROM_RESOURCE);
+#endif
+       }
+}
+
+
+int
+pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for (idx=0; idx<6; idx++) {
+               /* Only set up the requested stuff */
+               if (!(mask & (1<<idx)))
+                       continue;
+       
+               r = &dev->resource[idx];
+               if (r->flags & IORESOURCE_UNSET) {
+                       printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               cmd |= PCI_COMMAND_MEMORY;
+       if (cmd != old_cmd) {
+               printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+static int next_controller_index;
+
+struct pci_controller * __init
+pcibios_alloc_controller(void)
+{
+       struct pci_controller *hose;
+
+       hose = (struct pci_controller *)alloc_bootmem(sizeof(*hose));
+       memset(hose, 0, sizeof(struct pci_controller));
+
+       *hose_tail = hose;
+       hose_tail = &hose->next;
+
+       hose->index = next_controller_index++;
+
+       return hose;
+}
+
+#ifdef CONFIG_PPC_OF
+/*
+ * Functions below are used on OpenFirmware machines.
+ */
+static void
+make_one_node_map(struct device_node* node, u8 pci_bus)
+{
+       int *bus_range;
+       int len;
+
+       if (pci_bus >= pci_bus_count)
+               return;
+       bus_range = (int *) 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);
+               pci_to_OF_bus_map[pci_bus] = 0;
+       } else
+               pci_to_OF_bus_map[pci_bus] = bus_range[0];
+
+       for (node=node->child; node != 0;node = node->sibling) {
+               struct pci_dev* dev;
+               unsigned int *class_code, *reg;
+       
+               class_code = (unsigned int *) 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 = (unsigned int *)get_property(node, "reg", NULL);
+               if (!reg)
+                       continue;
+               dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+               if (!dev || !dev->subordinate)
+                       continue;
+               make_one_node_map(node, dev->subordinate->number);
+       }
+}
+       
+void
+pcibios_make_OF_bus_map(void)
+{
+       int i;
+       struct pci_controller* hose;
+       u8* of_prop_map;
+
+       pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL);
+       if (!pci_to_OF_bus_map) {
+               printk(KERN_ERR "Can't allocate OF bus map !\n");
+               return;
+       }
+
+       /* We fill the bus map with invalid values, that helps
+        * debugging.
+        */
+       for (i=0; i<pci_bus_count; i++)
+               pci_to_OF_bus_map[i] = 0xff;
+
+       /* For each hose, we begin searching bridges */
+       for(hose=hose_head; hose; hose=hose->next) {
+               struct device_node* node;       
+               node = (struct device_node *)hose->arch_data;
+               if (!node)
+                       continue;
+               make_one_node_map(node, hose->first_busno);
+       }
+       of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL);
+       if (of_prop_map)
+               memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count);
+#ifdef DEBUG
+       printk("PCI->OF bus map:\n");
+       for (i=0; i<pci_bus_count; i++) {
+               if (pci_to_OF_bus_map[i] == 0xff)
+                       continue;
+               printk("%d -> %d\n", i, pci_to_OF_bus_map[i]);
+       }
+#endif
+}
+
+typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);
+
+static struct device_node*
+scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data)
+{
+       struct device_node* sub_node;
+
+       for (; node != 0;node = node->sibling) {
+               unsigned int *class_code;
+       
+               if (filter(node, data))
+                       return node;
+
+               /* For PCI<->PCI bridges or CardBus bridges, we go down
+                * Note: some OFs create a parent node "multifunc-device" as
+                * a fake root for all functions of a multi-function device,
+                * we go down them as well.
+                */
+               class_code = (unsigned int *) 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"))
+                       continue;
+               sub_node = scan_OF_pci_childs(node->child, filter, data);
+               if (sub_node)
+                       return sub_node;
+       }
+       return NULL;
+}
+
+static int
+scan_OF_pci_childs_iterator(struct device_node* node, void* data)
+{
+       unsigned int *reg;
+       u8* fdata = (u8*)data;
+       
+       reg = (unsigned int *) get_property(node, "reg", NULL);
+       if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
+               && ((reg[0] >> 16) & 0xff) == fdata[0])
+               return 1;
+       return 0;
+}
+
+static struct device_node*
+scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
+{
+       u8 filter_data[2] = {bus, dev_fn};
+
+       return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
+}
+
+/*
+ * Scans the OF tree for a device node matching a PCI device
+ */
+struct device_node *
+pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
+{
+       struct pci_controller *hose;
+       struct device_node *node;
+       int busnr;
+
+       if (!have_of)
+               return NULL;
+       
+       /* Lookup the hose */
+       busnr = bus->number;
+       hose = pci_bus_to_hose(busnr);
+       if (!hose)
+               return NULL;
+
+       /* Check it has an OF node associated */
+       node = (struct device_node *) hose->arch_data;
+       if (!node)
+               return NULL;
+
+       /* Fixup bus number according to what OF think it is. */
+#ifdef CONFIG_PPC_PMAC
+       /* The G5 need a special case here. Basically, we don't remap all
+        * busses on it so we don't create the pci-OF-map. However, we do
+        * remap the AGP bus and so have to deal with it. A future better
+        * fix has to be done by making the remapping per-host and always
+        * filling the pci_to_OF map. --BenH
+        */
+       if (_machine == _MACH_Pmac && busnr >= 0xf0)
+               busnr -= 0xf0;
+       else
+#endif
+       if (pci_to_OF_bus_map)
+               busnr = pci_to_OF_bus_map[busnr];
+       if (busnr == 0xff)
+               return NULL;
+       
+       /* Now, lookup childs of the hose */
+       return scan_OF_childs_for_device(node->child, busnr, devfn);
+}
+EXPORT_SYMBOL(pci_busdev_to_OF_node);
+
+struct device_node*
+pci_device_to_OF_node(struct pci_dev *dev)
+{
+       return pci_busdev_to_OF_node(dev->bus, dev->devfn);
+}
+EXPORT_SYMBOL(pci_device_to_OF_node);
+
+/* This routine is meant to be used early during boot, when the
+ * PCI bus numbers have not yet been assigned, and you need to
+ * issue PCI config cycles to an OF device.
+ * It could also be used to "fix" RTAS config cycles if you want
+ * to set pci_assign_all_buses to 1 and still use RTAS for PCI
+ * config cycles.
+ */
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
+{
+       if (!have_of)
+               return NULL;
+       while(node) {
+               struct pci_controller* hose;
+               for (hose=hose_head;hose;hose=hose->next)
+                       if (hose->arch_data == node)
+                               return hose;
+               node=node->parent;
+       }
+       return NULL;
+}
+
+static int
+find_OF_pci_device_filter(struct device_node* node, void* data)
+{
+       return ((void *)node == data);
+}
+
+/*
+ * Returns the PCI device matching a given OF node
+ */
+int
+pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
+{
+       unsigned int *reg;
+       struct pci_controller* hose;
+       struct pci_dev* dev = NULL;
+       
+       if (!have_of)
+               return -ENODEV;
+       /* Make sure it's really a PCI device */
+       hose = pci_find_hose_for_OF_device(node);
+       if (!hose || !hose->arch_data)
+               return -ENODEV;
+       if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
+                       find_OF_pci_device_filter, (void *)node))
+               return -ENODEV;
+       reg = (unsigned int *) get_property(node, "reg", NULL);
+       if (!reg)
+               return -ENODEV;
+       *bus = (reg[0] >> 16) & 0xff;
+       *devfn = ((reg[0] >> 8) & 0xff);
+
+       /* Ok, here we need some tweak. If we have already renumbered
+        * all busses, we can't rely on the OF bus number any more.
+        * the pci_to_OF_bus_map is not enough as several PCI busses
+        * may match the same OF bus number.
+        */
+       if (!pci_to_OF_bus_map)
+               return 0;
+
+       for_each_pci_dev(dev)
+               if (pci_to_OF_bus_map[dev->bus->number] == *bus &&
+                               dev->devfn == *devfn) {
+                       *bus = dev->bus->number;
+                       pci_dev_put(dev);
+                       return 0;
+               }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(pci_device_from_OF_node);
+
+void __init
+pci_process_bridge_OF_ranges(struct pci_controller *hose,
+                          struct device_node *dev, int primary)
+{
+       static unsigned int static_lc_ranges[256] __initdata;
+       unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
+       unsigned int size;
+       int rlen = 0, orig_rlen;
+       int memno = 0;
+       struct resource *res;
+       int np, na = prom_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 = (unsigned int *) get_property(dev, "ranges", &rlen);
+       if (!dt_ranges)
+               return;
+       /* Sanity check, though hopefully that never happens */
+       if (rlen > sizeof(static_lc_ranges)) {
+               printk(KERN_WARNING "OF ranges property too large !\n");
+               rlen = sizeof(static_lc_ranges);
+       }
+       lc_ranges = static_lc_ranges;
+       memcpy(lc_ranges, dt_ranges, rlen);
+       orig_rlen = rlen;
+
+       /* Let's work on a copy of the "ranges" property instead of damaging
+        * the device-tree image in memory
+        */
+       ranges = lc_ranges;
+       prev = NULL;
+       while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+               if (prev) {
+                       if (prev[0] == ranges[0] && prev[1] == ranges[1] &&
+                               (prev[2] + prev[na+4]) == ranges[2] &&
+                               (prev[na+2] + prev[na+4]) == ranges[na+2]) {
+                               prev[na+4] += ranges[na+4];
+                               ranges[0] = 0;
+                               ranges += np;
+                               continue;
+                       }
+               }
+               prev = ranges;
+               ranges += np;
+       }
+
+       /*
+        * The ranges property is laid out as an array of elements,
+        * each of which comprises:
+        *   cells 0 - 2:       a PCI address
+        *   cells 3 or 3+4:    a CPU physical address
+        *                      (size depending on dev->n_addr_cells)
+        *   cells 4+5 or 5+6:  the size of the range
+        */
+       ranges = lc_ranges;
+       rlen = orig_rlen;
+       while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
+               res = NULL;
+               size = ranges[na+4];
+               switch ((ranges[0] >> 24) & 0x3) {
+               case 1:         /* I/O space */
+                       if (ranges[2] != 0)
+                               break;
+                       hose->io_base_phys = ranges[na+2];
+                       /* limit I/O space to 16MB */
+                       if (size > 0x01000000)
+                               size = 0x01000000;
+                       hose->io_base_virt = ioremap(ranges[na+2], size);
+                       if (primary)
+                               isa_io_base = (unsigned long) hose->io_base_virt;
+                       res = &hose->io_resource;
+                       res->flags = IORESOURCE_IO;
+                       res->start = ranges[2];
+                       DBG("PCI: IO 0x%lx -> 0x%lx\n",
+                                   res->start, res->start + size - 1);
+                       break;
+               case 2:         /* memory space */
+                       memno = 0;
+                       if (ranges[1] == 0 && ranges[2] == 0
+                           && ranges[na+4] <= (16 << 20)) {
+                               /* 1st 16MB, i.e. ISA memory area */
+                               if (primary)
+                                       isa_mem_base = ranges[na+2];
+                               memno = 1;
+                       }
+                       while (memno < 3 && hose->mem_resources[memno].flags)
+                               ++memno;
+                       if (memno == 0)
+                               hose->pci_mem_offset = ranges[na+2] - ranges[2];
+                       if (memno < 3) {
+                               res = &hose->mem_resources[memno];
+                               res->flags = IORESOURCE_MEM;
+                               if(ranges[0] & 0x40000000)
+                                       res->flags |= IORESOURCE_PREFETCH;
+                               res->start = ranges[na+2];
+                               DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno,
+                                           res->start, res->start + size - 1);
+                       }
+                       break;
+               }
+               if (res != NULL) {
+                       res->name = dev->full_name;
+                       res->end = res->start + size - 1;
+                       res->parent = NULL;
+                       res->sibling = NULL;
+                       res->child = NULL;
+               }
+               ranges += np;
+       }
+}
+
+/* We create the "pci-OF-bus-map" property now so it appears in the
+ * /proc device tree
+ */
+void __init
+pci_create_OF_bus_map(void)
+{
+       struct property* of_prop;
+       
+       of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
+       if (of_prop && find_path_device("/")) {
+               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);
+       }
+}
+
+static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct pci_dev *pdev;
+       struct device_node *np;
+
+       pdev = to_pci_dev (dev);
+       np = pci_device_to_OF_node(pdev);
+       if (np == NULL || np->full_name == NULL)
+               return 0;
+       return sprintf(buf, "%s", np->full_name);
+}
+static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
+
+#else /* CONFIG_PPC_OF */
+void pcibios_make_OF_bus_map(void)
+{
+}
+#endif /* CONFIG_PPC_OF */
+
+/* Add sysfs properties */
+void pcibios_add_platform_entries(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PPC_OF
+       device_create_file(&pdev->dev, &dev_attr_devspec);
+#endif /* CONFIG_PPC_OF */
+}
+
+
+#ifdef CONFIG_PPC_PMAC
+/*
+ * This set of routines checks for PCI<->PCI bridges that have closed
+ * IO resources and have child devices. It tries to re-open an IO
+ * window on them.
+ *
+ * This is a _temporary_ fix to workaround a problem with Apple's OF
+ * closing IO windows on P2P bridges when the OF drivers of cards
+ * below this bridge don't claim any IO range (typically ATI or
+ * Adaptec).
+ *
+ * A more complete fix would be to use drivers/pci/setup-bus.c, which
+ * involves a working pcibios_fixup_pbus_ranges(), some more care about
+ * ordering when creating the host bus resources, and maybe a few more
+ * minor tweaks
+ */
+
+/* Initialize bridges with base/limit values we have collected */
+static void __init
+do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
+{
+       struct pci_dev *bridge = bus->self;
+       struct pci_controller* hose = (struct pci_controller *)bridge->sysdata;
+       u32 l;
+       u16 w;
+       struct resource res;
+
+       if (bus->resource[0] == NULL)
+               return;
+       res = *(bus->resource[0]);
+
+       DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));
+       res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
+       res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
+       DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
+
+       /* Set up the top and bottom of the PCI I/O segment for this bus. */
+       pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+       l &= 0xffff000f;
+       l |= (res.start >> 8) & 0x00f0;
+       l |= res.end & 0xf000;
+       pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+       if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
+               l = (res.start >> 16) | (res.end & 0xffff0000);
+               pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l);
+       }
+
+       pci_read_config_word(bridge, PCI_COMMAND, &w);
+       w |= PCI_COMMAND_IO;
+       pci_write_config_word(bridge, PCI_COMMAND, w);
+
+#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */
+       if (enable_vga) {
+               pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w);
+               w |= PCI_BRIDGE_CTL_VGA;
+               pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w);
+       }
+#endif
+}
+
+/* This function is pretty basic and actually quite broken for the
+ * general case, it's enough for us right now though. It's supposed
+ * to tell us if we need to open an IO range at all or not and what
+ * size.
+ */
+static int __init
+check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
+{
+       struct pci_dev *dev;
+       int     i;
+       int     rc = 0;
+
+#define push_end(res, size) do { unsigned long __sz = (size) ; \
+       res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
+    } while (0)
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               u16 class = dev->class >> 8;
+
+               if (class == PCI_CLASS_DISPLAY_VGA ||
+                   class == PCI_CLASS_NOT_DEFINED_VGA)
+                       *found_vga = 1;
+               if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)
+                       rc |= check_for_io_childs(dev->subordinate, res, found_vga);
+               if (class == PCI_CLASS_BRIDGE_CARDBUS)
+                       push_end(res, 0xfff);
+
+               for (i=0; i<PCI_NUM_RESOURCES; i++) {
+                       struct resource *r;
+                       unsigned long r_size;
+
+                       if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI
+                           && i >= PCI_BRIDGE_RESOURCES)
+                               continue;
+                       r = &dev->resource[i];
+                       r_size = r->end - r->start;
+                       if (r_size < 0xfff)
+                               r_size = 0xfff;
+                       if (r->flags & IORESOURCE_IO && (r_size) != 0) {
+                               rc = 1;
+                               push_end(res, r_size);
+                       }
+               }
+       }
+
+       return rc;
+}
+
+/* Here we scan all P2P bridges of a given level that have a closed
+ * IO window. Note that the test for the presence of a VGA card should
+ * be improved to take into account already configured P2P bridges,
+ * currently, we don't see them and might end up configuring 2 bridges
+ * with VGA pass through enabled
+ */
+static void __init
+do_fixup_p2p_level(struct pci_bus *bus)
+{
+       struct pci_bus *b;
+       int i, parent_io;
+       int has_vga = 0;
+
+       for (parent_io=0; parent_io<4; parent_io++)
+               if (bus->resource[parent_io]
+                   && bus->resource[parent_io]->flags & IORESOURCE_IO)
+                       break;
+       if (parent_io >= 4)
+               return;
+
+       list_for_each_entry(b, &bus->children, node) {
+               struct pci_dev *d = b->self;
+               struct pci_controller* hose = (struct pci_controller *)d->sysdata;
+               struct resource *res = b->resource[0];
+               struct resource tmp_res;
+               unsigned long max;
+               int found_vga = 0;
+
+               memset(&tmp_res, 0, sizeof(tmp_res));
+               tmp_res.start = bus->resource[parent_io]->start;
+
+               /* We don't let low addresses go through that closed P2P bridge, well,
+                * that may not be necessary but I feel safer that way
+                */
+               if (tmp_res.start == 0)
+                       tmp_res.start = 0x1000;
+       
+               if (!list_empty(&b->devices) && res && res->flags == 0 &&
+                   res != bus->resource[parent_io] &&
+                   (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+                   check_for_io_childs(b, &tmp_res, &found_vga)) {
+                       u8 io_base_lo;
+
+                       printk(KERN_INFO "Fixing up IO bus %s\n", b->name);
+
+                       if (found_vga) {
+                               if (has_vga) {
+                                       printk(KERN_WARNING "Skipping VGA, already active"
+                                           " on bus segment\n");
+                                       found_vga = 0;
+                               } else
+                                       has_vga = 1;
+                       }
+                       pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);
+
+                       if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)
+                               max = ((unsigned long) hose->io_base_virt
+                                       - isa_io_base) + 0xffffffff;
+                       else
+                               max = ((unsigned long) hose->io_base_virt
+                                       - isa_io_base) + 0xffff;
+
+                       *res = tmp_res;
+                       res->flags = IORESOURCE_IO;
+                       res->name = b->name;
+               
+                       /* Find a resource in the parent where we can allocate */
+                       for (i = 0 ; i < 4; i++) {
+                               struct resource *r = bus->resource[i];
+                               if (!r)
+                                       continue;
+                               if ((r->flags & IORESOURCE_IO) == 0)
+                                       continue;
+                               DBG("Trying to allocate from %08lx, size %08lx from parent"
+                                   " res %d: %08lx -> %08lx\n",
+                                       res->start, res->end, i, r->start, r->end);
+                       
+                               if (allocate_resource(r, res, res->end + 1, res->start, max,
+                                   res->end + 1, NULL, NULL) < 0) {
+                                       DBG("Failed !\n");
+                                       continue;
+                               }
+                               do_update_p2p_io_resource(b, found_vga);
+                               break;
+                       }
+               }
+               do_fixup_p2p_level(b);
+       }
+}
+
+static void
+pcibios_fixup_p2p_bridges(void)
+{
+       struct pci_bus *b;
+
+       list_for_each_entry(b, &pci_root_buses, node)
+               do_fixup_p2p_level(b);
+}
+
+#endif /* CONFIG_PPC_PMAC */
+
+static int __init
+pcibios_init(void)
+{
+       struct pci_controller *hose;
+       struct pci_bus *bus;
+       int next_busno;
+
+       printk(KERN_INFO "PCI: Probing PCI hardware\n");
+
+       /* Scan all of the recorded PCI controllers.  */
+       for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
+               if (pci_assign_all_buses)
+                       hose->first_busno = next_busno;
+               hose->last_busno = 0xff;
+               bus = pci_scan_bus(hose->first_busno, hose->ops, hose);
+               hose->last_busno = bus->subordinate;
+               if (pci_assign_all_buses || next_busno <= hose->last_busno)
+                       next_busno = hose->last_busno + pcibios_assign_bus_offset;
+       }
+       pci_bus_count = next_busno;
+
+       /* OpenFirmware based machines need a map of OF bus
+        * numbers vs. kernel bus numbers since we may have to
+        * remap them.
+        */
+       if (pci_assign_all_buses && have_of)
+               pcibios_make_OF_bus_map();
+
+       /* Do machine dependent PCI interrupt routing */
+       if (ppc_md.pci_swizzle && ppc_md.pci_map_irq)
+               pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq);
+
+       /* Call machine dependent fixup */
+       if (ppc_md.pcibios_fixup)
+               ppc_md.pcibios_fixup();
+
+       /* Allocate and assign resources */
+       pcibios_allocate_bus_resources(&pci_root_buses);
+       pcibios_allocate_resources(0);
+       pcibios_allocate_resources(1);
+#ifdef CONFIG_PPC_PMAC
+       pcibios_fixup_p2p_bridges();
+#endif /* CONFIG_PPC_PMAC */
+       pcibios_assign_resources();
+
+       /* Call machine dependent post-init code */
+       if (ppc_md.pcibios_after_init)
+               ppc_md.pcibios_after_init();
+
+       return 0;
+}
+
+subsys_initcall(pcibios_init);
+
+unsigned char __init
+common_swizzle(struct pci_dev *dev, unsigned char *pinp)
+{
+       struct pci_controller *hose = dev->sysdata;
+
+       if (dev->bus->number != hose->first_busno) {
+               u8 pin = *pinp;
+               do {
+                       pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+                       /* Move up the chain of bridges. */
+                       dev = dev->bus->self;
+               } while (dev->bus->self);
+               *pinp = pin;
+
+               /* The slot is the idsel of the last bridge. */
+       }
+       return PCI_SLOT(dev->devfn);
+}
+
+unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
+                            unsigned long start, unsigned long size)
+{
+       return start;
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+       struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
+       unsigned long io_offset;
+       struct resource *res;
+       int i;
+
+       io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
+       if (bus->parent == NULL) {
+               /* This is a host bridge - fill in its resources */
+               hose->bus = bus;
+
+               bus->resource[0] = res = &hose->io_resource;
+               if (!res->flags) {
+                       if (io_offset)
+                               printk(KERN_ERR "I/O resource not set for host"
+                                      " bridge %d\n", hose->index);
+                       res->start = 0;
+                       res->end = IO_SPACE_LIMIT;
+                       res->flags = IORESOURCE_IO;
+               }
+               res->start += io_offset;
+               res->end += io_offset;
+
+               for (i = 0; i < 3; ++i) {
+                       res = &hose->mem_resources[i];
+                       if (!res->flags) {
+                               if (i > 0)
+                                       continue;
+                               printk(KERN_ERR "Memory resource not set for "
+                                      "host bridge %d\n", hose->index);
+                               res->start = hose->pci_mem_offset;
+                               res->end = ~0U;
+                               res->flags = IORESOURCE_MEM;
+                       }
+                       bus->resource[i+1] = res;
+               }
+       } else {
+               /* This is a subordinate bridge */
+               pci_read_bridge_bases(bus);
+
+               for (i = 0; i < 4; ++i) {
+                       if ((res = bus->resource[i]) == NULL)
+                               continue;
+                       if (!res->flags)
+                               continue;
+                       if (io_offset && (res->flags & IORESOURCE_IO)) {
+                               res->start += io_offset;
+                               res->end += io_offset;
+                       } else if (hose->pci_mem_offset
+                                  && (res->flags & IORESOURCE_MEM)) {
+                               res->start += hose->pci_mem_offset;
+                               res->end += hose->pci_mem_offset;
+                       }
+               }
+       }
+
+       if (ppc_md.pcibios_fixup_bus)
+               ppc_md.pcibios_fixup_bus(bus);
+}
+
+char __init *pcibios_setup(char *str)
+{
+       return str;
+}
+
+/* the next one is stolen from the alpha port... */
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+       pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+       /* XXX FIXME - update OF device tree node interrupt property */
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+       u16 cmd, old_cmd;
+       int idx;
+       struct resource *r;
+
+       if (ppc_md.pcibios_enable_device_hook)
+               if (ppc_md.pcibios_enable_device_hook(dev, 0))
+                       return -EINVAL;
+               
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       old_cmd = cmd;
+       for (idx=0; idx<6; idx++) {
+               r = &dev->resource[idx];
+               if (r->flags & IORESOURCE_UNSET) {
+                       printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
+                       return -EINVAL;
+               }
+               if (r->flags & IORESOURCE_IO)
+                       cmd |= PCI_COMMAND_IO;
+               if (r->flags & IORESOURCE_MEM)
+                       cmd |= PCI_COMMAND_MEMORY;
+       }
+       if (cmd != old_cmd) {
+               printk("PCI: Enabling device %s (%04x -> %04x)\n",
+                      pci_name(dev), old_cmd, cmd);
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       return 0;
+}
+
+struct pci_controller*
+pci_bus_to_hose(int bus)
+{
+       struct pci_controller* hose = hose_head;
+
+       for (; hose; hose = hose->next)
+               if (bus >= hose->first_busno && bus <= hose->last_busno)
+                       return hose;
+       return NULL;
+}
+
+void __iomem *
+pci_bus_io_base(unsigned int bus)
+{
+       struct pci_controller *hose;
+
+       hose = pci_bus_to_hose(bus);
+       if (!hose)
+               return NULL;
+       return hose->io_base_virt;
+}
+
+unsigned long
+pci_bus_io_base_phys(unsigned int bus)
+{
+       struct pci_controller *hose;
+
+       hose = pci_bus_to_hose(bus);
+       if (!hose)
+               return 0;
+       return hose->io_base_phys;
+}
+
+unsigned long
+pci_bus_mem_base_phys(unsigned int bus)
+{
+       struct pci_controller *hose;
+
+       hose = pci_bus_to_hose(bus);
+       if (!hose)
+               return 0;
+       return hose->pci_mem_offset;
+}
+
+unsigned long
+pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
+{
+       /* Hack alert again ! See comments in chrp_pci.c
+        */
+       struct pci_controller* hose =
+               (struct pci_controller *)pdev->sysdata;
+       if (hose && res->flags & IORESOURCE_MEM)
+               return res->start - hose->pci_mem_offset;
+       /* We may want to do something with IOs here... */
+       return res->start;
+}
+
+
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+                                              unsigned long *offset,
+                                              enum pci_mmap_state mmap_state)
+{
+       struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+       unsigned long io_offset = 0;
+       int i, res_bit;
+
+       if (hose == 0)
+               return NULL;            /* should never happen */
+
+       /* If memory, add on the PCI bridge address offset */
+       if (mmap_state == pci_mmap_mem) {
+               *offset += hose->pci_mem_offset;
+               res_bit = IORESOURCE_MEM;
+       } else {
+               io_offset = hose->io_base_virt - ___IO_BASE;
+               *offset += io_offset;
+               res_bit = IORESOURCE_IO;
+       }
+
+       /*
+        * Check that the offset requested corresponds to one of the
+        * resources of the device.
+        */
+       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+               struct resource *rp = &dev->resource[i];
+               int flags = rp->flags;
+
+               /* treat ROM as memory (should be already) */
+               if (i == PCI_ROM_RESOURCE)
+                       flags |= IORESOURCE_MEM;
+
+               /* Active and same type? */
+               if ((flags & res_bit) == 0)
+                       continue;
+
+               /* In the range of this resource? */
+               if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
+                       continue;
+
+               /* found it! construct the final physical address */
+               if (mmap_state == pci_mmap_io)
+                       *offset += hose->io_base_phys - io_offset;
+               return rp;
+       }
+
+       return NULL;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+                                     pgprot_t protection,
+                                     enum pci_mmap_state mmap_state,
+                                     int write_combine)
+{
+       unsigned long prot = pgprot_val(protection);
+
+       /* Write combine is always 0 on non-memory space mappings. On
+        * memory space, if the user didn't pass 1, we check for a
+        * "prefetchable" resource. This is a bit hackish, but we use
+        * this to workaround the inability of /sysfs to provide a write
+        * combine bit
+        */
+       if (mmap_state != pci_mmap_mem)
+               write_combine = 0;
+       else if (write_combine == 0) {
+               if (rp->flags & IORESOURCE_PREFETCH)
+                       write_combine = 1;
+       }
+
+       /* XXX would be nice to have a way to ask for write-through */
+       prot |= _PAGE_NO_CACHE;
+       if (write_combine)
+               prot &= ~_PAGE_GUARDED;
+       else
+               prot |= _PAGE_GUARDED;
+
+       printk("PCI map for %s:%lx, prot: %lx\n", pci_name(dev), rp->start,
+              prot);
+
+       return __pgprot(prot);
+}
+
+/*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+                                 unsigned long pfn,
+                                 unsigned long size,
+                                 pgprot_t protection)
+{
+       struct pci_dev *pdev = NULL;
+       struct resource *found = NULL;
+       unsigned long prot = pgprot_val(protection);
+       unsigned long offset = pfn << PAGE_SHIFT;
+       int i;
+
+       if (page_is_ram(pfn))
+               return prot;
+
+       prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+       for_each_pci_dev(pdev) {
+               for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+                       struct resource *rp = &pdev->resource[i];
+                       int flags = rp->flags;
+
+                       /* Active and same type? */
+                       if ((flags & IORESOURCE_MEM) == 0)
+                               continue;
+                       /* In the range of this resource? */
+                       if (offset < (rp->start & PAGE_MASK) ||
+                           offset > rp->end)
+                               continue;
+                       found = rp;
+                       break;
+               }
+               if (found)
+                       break;
+       }
+       if (found) {
+               if (found->flags & IORESOURCE_PREFETCH)
+                       prot &= ~_PAGE_GUARDED;
+               pci_dev_put(pdev);
+       }
+
+       DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+       return __pgprot(prot);
+}
+
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture.  The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                       enum pci_mmap_state mmap_state,
+                       int write_combine)
+{
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       struct resource *rp;
+       int ret;
+
+       rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+       if (rp == NULL)
+               return -EINVAL;
+
+       vma->vm_pgoff = offset >> PAGE_SHIFT;
+       vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+       vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+                                                 vma->vm_page_prot,
+                                                 mmap_state, write_combine);
+
+       ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+                              vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+       return ret;
+}
+
+/* Obsolete functions. Should be removed once the symbios driver
+ * is fixed
+ */
+unsigned long
+phys_to_bus(unsigned long pa)
+{
+       struct pci_controller *hose;
+       int i;
+
+       for (hose = hose_head; hose; hose = hose->next) {
+               for (i = 0; i < 3; ++i) {
+                       if (pa >= hose->mem_resources[i].start
+                           && pa <= hose->mem_resources[i].end) {
+                               /*
+                                * XXX the hose->pci_mem_offset really
+                                * only applies to mem_resources[0].
+                                * We need a way to store an offset for
+                                * the others.  -- paulus
+                                */
+                               if (i == 0)
+                                       pa -= hose->pci_mem_offset;
+                               return pa;
+                       }
+               }
+       }
+       /* hmmm, didn't find it */
+       return 0;
+}
+
+unsigned long
+pci_phys_to_bus(unsigned long pa, int busnr)
+{
+       struct pci_controller* hose = pci_bus_to_hose(busnr);
+       if (!hose)
+               return pa;
+       return pa - hose->pci_mem_offset;
+}
+
+unsigned long
+pci_bus_to_phys(unsigned int ba, int busnr)
+{
+       struct pci_controller* hose = pci_bus_to_hose(busnr);
+       if (!hose)
+               return ba;
+       return ba + hose->pci_mem_offset;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory.  Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+       struct pci_controller* hose;
+       long result = -EOPNOTSUPP;
+
+       /* Argh ! Please forgive me for that hack, but that's the
+        * simplest way to get existing XFree to not lockup on some
+        * G5 machines... So when something asks for bus 0 io base
+        * (bus 0 is HT root), we return the AGP one instead.
+        */
+#ifdef CONFIG_PPC_PMAC
+       if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4"))
+               if (bus == 0)
+                       bus = 0xf0;
+#endif /* CONFIG_PPC_PMAC */
+
+       hose = pci_bus_to_hose(bus);
+       if (!hose)
+               return -ENODEV;
+
+       switch (which) {
+       case IOBASE_BRIDGE_NUMBER:
+               return (long)hose->first_busno;
+       case IOBASE_MEMORY:
+               return (long)hose->pci_mem_offset;
+       case IOBASE_IO:
+               return (long)hose->io_base_phys;
+       case IOBASE_ISA_IO:
+               return (long)isa_io_base;
+       case IOBASE_ISA_MEM:
+               return (long)isa_mem_base;
+       }
+
+       return result;
+}
+
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+                         const struct resource *rsrc,
+                         u64 *start, u64 *end)
+{
+       struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+       unsigned long offset = 0;
+
+       if (hose == NULL)
+               return;
+
+       if (rsrc->flags & IORESOURCE_IO)
+               offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+
+       *start = rsrc->start + offset;
+       *end = rsrc->end + offset;
+}
+
+void __init
+pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
+                 int flags, char *name)
+{
+       res->start = start;
+       res->end = end;
+       res->flags = flags;
+       res->name = name;
+       res->parent = NULL;
+       res->sibling = NULL;
+       res->child = NULL;
+}
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
+{
+       unsigned long start = pci_resource_start(dev, bar);
+       unsigned long len = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len)
+               return NULL;
+       if (max && len > max)
+               len = max;
+       if (flags & IORESOURCE_IO)
+               return ioport_map(start, len);
+       if (flags & IORESOURCE_MEM)
+               /* Not checking IORESOURCE_CACHEABLE because PPC does
+                * not currently distinguish between ioremap and
+                * ioremap_nocache.
+                */
+               return ioremap(start, len);
+       /* What? */
+       return NULL;
+}
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       /* Nothing to do */
+}
+EXPORT_SYMBOL(pci_iomap);
+EXPORT_SYMBOL(pci_iounmap);
+
+unsigned long pci_address_to_pio(phys_addr_t address)
+{
+       struct pci_controller* hose = hose_head;
+
+       for (; hose; hose = hose->next) {
+               unsigned int size = hose->io_resource.end -
+                       hose->io_resource.start + 1;
+               if (address >= hose->io_base_phys &&
+                   address < (hose->io_base_phys + size)) {
+                       unsigned long base =
+                               (unsigned long)hose->io_base_virt - _IO_BASE;
+                       return base + (address - hose->io_base_phys);
+               }
+       }
+       return (unsigned int)-1;
+}
+EXPORT_SYMBOL(pci_address_to_pio);
+
+/*
+ * Null PCI config access functions, for the case when we can't
+ * find a hose.
+ */
+#define NULL_PCI_OP(rw, size, type)                                    \
+static int                                                             \
+null_##rw##_config_##size(struct pci_dev *dev, int offset, type val)   \
+{                                                                      \
+       return PCIBIOS_DEVICE_NOT_FOUND;                                \
+}
+
+static int
+null_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                int len, u32 *val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static int
+null_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+                 int len, u32 val)
+{
+       return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+static struct pci_ops null_pci_ops =
+{
+       null_read_config,
+       null_write_config
+};
+
+/*
+ * These functions are used early on before PCI scanning is done
+ * and all of the pci_dev and pci_bus structures have been created.
+ */
+static struct pci_bus *
+fake_pci_bus(struct pci_controller *hose, int busnr)
+{
+       static struct pci_bus bus;
+
+       if (hose == 0) {
+               hose = pci_bus_to_hose(busnr);
+               if (hose == 0)
+                       printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr);
+       }
+       bus.number = busnr;
+       bus.sysdata = hose;
+       bus.ops = hose? hose->ops: &null_pci_ops;
+       return &bus;
+}
+
+#define EARLY_PCI_OP(rw, size, type)                                   \
+int early_##rw##_config_##size(struct pci_controller *hose, int bus,   \
+                              int devfn, int offset, type value)       \
+{                                                                      \
+       return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus),    \
+                                           devfn, offset, value);      \
+}
+
+EARLY_PCI_OP(read, byte, u8 *)
+EARLY_PCI_OP(read, word, u16 *)
+EARLY_PCI_OP(read, dword, u32 *)
+EARLY_PCI_OP(write, byte, u8)
+EARLY_PCI_OP(write, word, u16)
+EARLY_PCI_OP(write, dword, u32)
index 16d9a904f3cbc35b24a6341a1928663829d163ed..d9a459c144d81da76bb3023f3f5d89cddca28d95 100644 (file)
@@ -230,8 +230,7 @@ EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
 #endif /* CONFIG_8xx */
-#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx) ||\
-       defined(CONFIG_83xx)
+#if defined(CONFIG_8xx) || defined(CONFIG_40x)
 EXPORT_SYMBOL(__res);
 #endif
 
index 02e2115323e49b5f6d43fcd782cea4843c76527c..d50c8df0183e524283ea966ccc728b4b1025676e 100644 (file)
@@ -1627,6 +1627,11 @@ static void of_node_release(struct kref *kref)
                kfree(prop->value);
                kfree(prop);
                prop = next;
+
+               if (!prop) {
+                       prop = node->deadprops;
+                       node->deadprops = NULL;
+               }
        }
        kfree(node->intrs);
        kfree(node->full_name);
@@ -1774,22 +1779,32 @@ static int __init prom_reconfig_setup(void)
 __initcall(prom_reconfig_setup);
 #endif
 
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-unsigned char *get_property(struct device_node *np, const char *name,
-                           int *lenp)
+struct property *of_find_property(struct device_node *np, const char *name,
+                                 int *lenp)
 {
        struct property *pp;
 
+       read_lock(&devtree_lock);
        for (pp = np->properties; pp != 0; pp = pp->next)
                if (strcmp(pp->name, name) == 0) {
                        if (lenp != 0)
                                *lenp = pp->length;
-                       return pp->value;
+                       break;
                }
-       return NULL;
+       read_unlock(&devtree_lock);
+
+       return pp;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *get_property(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);
 
@@ -1823,4 +1838,82 @@ int prom_add_property(struct device_node* np, struct property* prop)
        return 0;
 }
 
+/*
+ * Remove a property from a node.  Note that we don't actually
+ * remove it, since we have given out who-knows-how-many pointers
+ * to the data using get-property.  Instead we just move the property
+ * to the "dead properties" list, so it won't be found any more.
+ */
+int prom_remove_property(struct device_node *np, struct property *prop)
+{
+       struct property **next;
+       int found = 0;
 
+       write_lock(&devtree_lock);
+       next = &np->properties;
+       while (*next) {
+               if (*next == prop) {
+                       /* found the node */
+                       *next = prop->next;
+                       prop->next = np->deadprops;
+                       np->deadprops = prop;
+                       found = 1;
+                       break;
+               }
+               next = &(*next)->next;
+       }
+       write_unlock(&devtree_lock);
+
+       if (!found)
+               return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+       /* try to remove the proc node as well */
+       if (np->pde)
+               proc_device_tree_remove_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+       return 0;
+}
+
+/*
+ * Update a property in a node.  Note that we don't actually
+ * remove it, since we have given out who-knows-how-many pointers
+ * to the data using get-property.  Instead we just move the property
+ * to the "dead properties" list, and add the new property to the
+ * property list
+ */
+int prom_update_property(struct device_node *np,
+                        struct property *newprop,
+                        struct property *oldprop)
+{
+       struct property **next;
+       int found = 0;
+
+       write_lock(&devtree_lock);
+       next = &np->properties;
+       while (*next) {
+               if (*next == oldprop) {
+                       /* found the node */
+                       newprop->next = oldprop->next;
+                       *next = newprop;
+                       oldprop->next = np->deadprops;
+                       np->deadprops = oldprop;
+                       found = 1;
+                       break;
+               }
+               next = &(*next)->next;
+       }
+       write_unlock(&devtree_lock);
+
+       if (!found)
+               return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_update_prop(np->pde, newprop, oldprop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+       return 0;
+}
index d963a12ec640007269d5be45a63a64a73f04cb1b..7881ec96ef117ff3a02580c95c236771e0593a73 100644 (file)
@@ -605,7 +605,8 @@ static void __init early_cmdline_parse(void)
        opt = strstr(RELOC(prom_cmd_line), RELOC("crashkernel="));
        if (opt) {
                opt += 12;
-               RELOC(prom_crashk_size) = prom_memparse(opt, &opt);
+               RELOC(prom_crashk_size) = 
+                       prom_memparse(opt, (const char **)&opt);
 
                if (ALIGN(RELOC(prom_crashk_size), 0x1000000) !=
                        RELOC(prom_crashk_size)) {
index 309ae1d5fa77c0d007d05ff5560a0f45fbc1aed5..a8099c806150618e34dab60d7f7df036aa9eed29 100644 (file)
@@ -113,7 +113,8 @@ static unsigned int of_bus_default_get_flags(u32 *addr)
 
 static int of_bus_pci_match(struct device_node *np)
 {
-       return !strcmp(np->type, "pci");
+       /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
+       return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
 }
 
 static void of_bus_pci_count_cells(struct device_node *np,
index 4b9cfe4637b1fcff56cf698f15e250101d28ffe5..7fe4a5c944c9655e60c126ce1dabe0fe9027d0fb 100644 (file)
@@ -36,6 +36,11 @@ struct rtas_t rtas = {
        .lock = SPIN_LOCK_UNLOCKED
 };
 
+struct rtas_suspend_me_data {
+       long waiting;
+       struct rtas_args *args;
+};
+
 EXPORT_SYMBOL(rtas);
 
 DEFINE_SPINLOCK(rtas_data_buf_lock);
@@ -556,6 +561,80 @@ void rtas_os_term(char *str)
        } while (status == RTAS_BUSY);
 }
 
+static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
+#ifdef CONFIG_PPC_PSERIES
+static void rtas_percpu_suspend_me(void *info)
+{
+       long rc;
+       long flags;
+       struct rtas_suspend_me_data *data =
+               (struct rtas_suspend_me_data *)info;
+
+       /*
+        * We use "waiting" to indicate our state.  As long
+        * as it is >0, we are still trying to all join up.
+        * If it goes to 0, we have successfully joined up and
+        * one thread got H_Continue.  If any error happens,
+        * we set it to <0.
+        */
+       local_irq_save(flags);
+       do {
+               rc = plpar_hcall_norets(H_JOIN);
+               smp_rmb();
+       } while (rc == H_Success && data->waiting > 0);
+       if (rc == H_Success)
+               goto out;
+
+       if (rc == H_Continue) {
+               data->waiting = 0;
+               rtas_call(ibm_suspend_me_token, 0, 1,
+                         data->args->args);
+       } else {
+               data->waiting = -EBUSY;
+               printk(KERN_ERR "Error on H_Join hypervisor call\n");
+       }
+
+out:
+       /* before we restore interrupts, make sure we don't
+        * generate a spurious soft lockup errors
+        */
+       touch_softlockup_watchdog();
+       local_irq_restore(flags);
+       return;
+}
+
+static int rtas_ibm_suspend_me(struct rtas_args *args)
+{
+       int i;
+
+       struct rtas_suspend_me_data data;
+
+       data.waiting = 1;
+       data.args = args;
+
+       /* Call function on all CPUs.  One of us will make the
+        * rtas call
+        */
+       if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0))
+               data.waiting = -EINVAL;
+
+       if (data.waiting != 0)
+               printk(KERN_ERR "Error doing global join\n");
+
+       /* Prod each CPU.  This won't hurt, and will wake
+        * anyone we successfully put to sleep with H_Join
+        */
+       for_each_cpu(i)
+               plpar_hcall_norets(H_PROD, i);
+
+       return data.waiting;
+}
+#else /* CONFIG_PPC_PSERIES */
+static int rtas_ibm_suspend_me(struct rtas_args *args)
+{
+       return -ENOSYS;
+}
+#endif
 
 asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
 {
@@ -563,6 +642,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
        unsigned long flags;
        char *buff_copy, *errbuf = NULL;
        int nargs;
+       int rc;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -581,6 +661,17 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
                           nargs * sizeof(rtas_arg_t)) != 0)
                return -EFAULT;
 
+       if (args.token == RTAS_UNKNOWN_SERVICE)
+               return -EINVAL;
+
+       /* Need to handle ibm,suspend_me call specially */
+       if (args.token == ibm_suspend_me_token) {
+               rc = rtas_ibm_suspend_me(&args);
+               if (rc)
+                       return rc;
+               goto copy_return;
+       }
+
        buff_copy = get_errorlog_buffer();
 
        spin_lock_irqsave(&rtas.lock, flags);
@@ -604,6 +695,7 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
                kfree(buff_copy);
        }
 
+ copy_return:
        /* Copy out args. */
        if (copy_to_user(uargs->args + nargs,
                         args.args + nargs,
@@ -675,8 +767,10 @@ void __init rtas_initialize(void)
         * the stop-self token if any
         */
 #ifdef CONFIG_PPC64
-       if (_machine == PLATFORM_PSERIES_LPAR)
+       if (_machine == PLATFORM_PSERIES_LPAR) {
                rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);
+               ibm_suspend_me_token = rtas_token("ibm,suspend-me");
+       }
 #endif
        rtas_rmo_buf = lmb_alloc_base(RTAS_RMOBUF_MAX, PAGE_SIZE, rtas_region);
 
index d5c52fae023a1b996f71f5e38a1ed0d5964c9d3e..be12041c0fc5404ab8b811050f45de883c225631 100644 (file)
@@ -100,7 +100,8 @@ void machine_shutdown(void)
 void machine_restart(char *cmd)
 {
        machine_shutdown();
-       ppc_md.restart(cmd);
+       if (ppc_md.restart)
+               ppc_md.restart(cmd);
 #ifdef CONFIG_SMP
        smp_send_stop();
 #endif
@@ -112,7 +113,8 @@ void machine_restart(char *cmd)
 void machine_power_off(void)
 {
        machine_shutdown();
-       ppc_md.power_off();
+       if (ppc_md.power_off)
+               ppc_md.power_off();
 #ifdef CONFIG_SMP
        smp_send_stop();
 #endif
@@ -129,7 +131,8 @@ EXPORT_SYMBOL_GPL(pm_power_off);
 void machine_halt(void)
 {
        machine_shutdown();
-       ppc_md.halt();
+       if (ppc_md.halt)
+               ppc_md.halt();
 #ifdef CONFIG_SMP
        smp_send_stop();
 #endif
index 56f50e91bddbcb612201fdc4d34d0a2dd8b7b633..c4a294d657b92c23eee484902e6a963e4e0f3ab5 100644 (file)
@@ -431,7 +431,7 @@ void timer_interrupt(struct pt_regs * regs)
        profile_tick(CPU_PROFILING, regs);
 
 #ifdef CONFIG_PPC_ISERIES
-       get_paca()->lppaca.int_dword.fields.decr_int = 0;
+       get_lppaca()->int_dword.fields.decr_int = 0;
 #endif
 
        while ((ticks = tb_ticks_since(per_cpu(last_jiffy, cpu)))
index 13c41495fe06309e55311166eb8e8dfaa6c2b834..13c655ba2841aac42db44ddb6f2f76862eff8ffe 100644 (file)
@@ -76,7 +76,7 @@ static void vio_bus_shutdown(struct device *dev)
        struct vio_dev *viodev = to_vio_dev(dev);
        struct vio_driver *viodrv = to_vio_driver(dev->driver);
 
-       if (viodrv->shutdown)
+       if (dev->driver && viodrv->shutdown)
                viodrv->shutdown(viodev);
 }
 
@@ -91,9 +91,6 @@ int vio_register_driver(struct vio_driver *viodrv)
 
        /* fill in 'struct driver' fields */
        viodrv->driver.bus = &vio_bus_type;
-       viodrv->driver.probe = vio_bus_probe;
-       viodrv->driver.remove = vio_bus_remove;
-       viodrv->driver.shutdown = vio_bus_shutdown;
 
        return driver_register(&viodrv->driver);
 }
@@ -295,4 +292,7 @@ struct bus_type vio_bus_type = {
        .name = "vio",
        .uevent = vio_hotplug,
        .match = vio_bus_match,
+       .probe = vio_bus_probe,
+       .remove = vio_bus_remove,
+       .shutdown = vio_bus_shutdown,
 };
index 35bd03c41dd19727601e15f9169bc8807f50fb75..8362fa272ca58e9699c88c155c535a2e59fb4aeb 100644 (file)
 void __spin_yield(raw_spinlock_t *lock)
 {
        unsigned int lock_value, holder_cpu, yield_count;
-       struct paca_struct *holder_paca;
 
        lock_value = lock->slock;
        if (lock_value == 0)
                return;
        holder_cpu = lock_value & 0xffff;
        BUG_ON(holder_cpu >= NR_CPUS);
-       holder_paca = &paca[holder_cpu];
-       yield_count = holder_paca->lppaca.yield_count;
+       yield_count = lppaca[holder_cpu].yield_count;
        if ((yield_count & 1) == 0)
                return;         /* virtual cpu is currently running */
        rmb();
@@ -60,15 +58,13 @@ void __rw_yield(raw_rwlock_t *rw)
 {
        int lock_value;
        unsigned int holder_cpu, yield_count;
-       struct paca_struct *holder_paca;
 
        lock_value = rw->lock;
        if (lock_value >= 0)
                return;         /* no write lock at present */
        holder_cpu = lock_value & 0xffff;
        BUG_ON(holder_cpu >= NR_CPUS);
-       holder_paca = &paca[holder_cpu];
-       yield_count = holder_paca->lppaca.yield_count;
+       yield_count = lppaca[holder_cpu].yield_count;
        if ((yield_count & 1) == 0)
                return;         /* virtual cpu is currently running */
        rmb();
index 71615eb70b2be53975e6c83bca0665107ed6bc48..cc2535be3a73641326f49c4bb73233729ce7d314 100644 (file)
@@ -140,19 +140,19 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 
        switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC64
-               case RS64:
+               case PPC_OPROFILE_RS64:
                        model = &op_model_rs64;
                        break;
-               case POWER4:
+               case PPC_OPROFILE_POWER4:
                        model = &op_model_power4;
                        break;
 #else
-               case G4:
+               case PPC_OPROFILE_G4:
                        model = &op_model_7450;
                        break;
 #endif
 #ifdef CONFIG_FSL_BOOKE
-               case BOOKE:
+               case PPC_OPROFILE_BOOKE:
                        model = &op_model_fsl_booke;
                        break;
 #endif
index b20812d460e6edee41ee7eedf165dbba1a15cbff..7675e675dce1dab1e76d34bc8acf42dfd3357b64 100644 (file)
@@ -7,6 +7,7 @@ choice
 
 config MPC834x_SYS
        bool "Freescale MPC834x SYS"
+       select DEFAULT_UIMAGE
        help
          This option enables support for the MPC 834x SYS evaluation board.
 
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
new file mode 100644 (file)
index 0000000..2098dd0
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * arch/powerpc/platforms/83xx/mpc834x_sys.c
+ *
+ * MPC834x SYS board specific routines
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc83xx.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc83xx.h"
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+#ifdef CONFIG_PCI
+extern int mpc83xx_pci2_busno;
+
+static int
+mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+       static char pci_irq_table[][4] =
+           /*
+            *      PCI IDSEL/INTPIN->INTLINE
+            *       A      B      C      D
+            */
+       {
+               {PIRQA, PIRQB, PIRQC, PIRQD},   /* idsel 0x11 */
+               {PIRQC, PIRQD, PIRQA, PIRQB},   /* idsel 0x12 */
+               {PIRQD, PIRQA, PIRQB, PIRQC},   /* idsel 0x13 */
+               {0, 0, 0, 0},
+               {PIRQA, PIRQB, PIRQC, PIRQD},   /* idsel 0x15 */
+               {PIRQD, PIRQA, PIRQB, PIRQC},   /* idsel 0x16 */
+               {PIRQC, PIRQD, PIRQA, PIRQB},   /* idsel 0x17 */
+               {PIRQB, PIRQC, PIRQD, PIRQA},   /* idsel 0x18 */
+               {0, 0, 0, 0},                   /* idsel 0x19 */
+               {0, 0, 0, 0},                   /* idsel 0x20 */
+       };
+
+       const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
+       return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static int
+mpc83xx_exclude_device(u_char bus, u_char devfn)
+{
+       if (bus == 0 && PCI_SLOT(devfn) == 0)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       if (mpc83xx_pci2_busno)
+               if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
+                       return PCIBIOS_DEVICE_NOT_FOUND;
+       return PCIBIOS_SUCCESSFUL;
+}
+#endif /* CONFIG_PCI */
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc834x_sys_setup_arch(void)
+{
+       struct device_node *np;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc834x_sys_setup_arch()", 0);
+
+       np = of_find_node_by_type(NULL, "cpu");
+       if (np != 0) {
+               unsigned int *fp = (int *) get_property(np, "clock-frequency", NULL);
+               if (fp != 0)
+                       loops_per_jiffy = *fp / HZ;
+               else
+                       loops_per_jiffy = 50000000 / HZ;
+               of_node_put(np);
+       }
+
+#ifdef CONFIG_PCI
+       for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+               add_bridge(np);
+
+       ppc_md.pci_swizzle = common_swizzle;
+       ppc_md.pci_map_irq = mpc83xx_map_irq;
+       ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef  CONFIG_ROOT_NFS
+               ROOT_DEV = Root_NFS;
+#else
+               ROOT_DEV = Root_HDA1;
+#endif
+}
+
+void __init
+mpc834x_sys_init_IRQ(void)
+{
+       u8 senses[8] = {
+               0,                      /* EXT 0 */
+               IRQ_SENSE_LEVEL,        /* EXT 1 */
+               IRQ_SENSE_LEVEL,        /* EXT 2 */
+               0,                      /* EXT 3 */
+#ifdef CONFIG_PCI
+               IRQ_SENSE_LEVEL,        /* EXT 4 */
+               IRQ_SENSE_LEVEL,        /* EXT 5 */
+               IRQ_SENSE_LEVEL,        /* EXT 6 */
+               IRQ_SENSE_LEVEL,        /* EXT 7 */
+#else
+               0,                      /* EXT 4 */
+               0,                      /* EXT 5 */
+               0,                      /* EXT 6 */
+               0,                      /* EXT 7 */
+#endif
+       };
+
+       ipic_init(get_immrbase() + 0x00700, 0, 0, senses, 8);
+
+       /* Initialize the default interrupt mapping priorities,
+        * in case the boot rom changed something on us.
+        */
+       ipic_set_default_priority();
+}
+
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong   ds1374_get_rtc_time(void);
+extern int     ds1374_set_rtc_time(ulong);
+
+static int __init
+mpc834x_rtc_hookup(void)
+{
+       struct timespec tv;
+
+       ppc_md.get_rtc_time = ds1374_get_rtc_time;
+       ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+       tv.tv_nsec = 0;
+       tv.tv_sec = (ppc_md.get_rtc_time)();
+       do_settimeofday(&tv);
+
+       return 0;
+}
+late_initcall(mpc834x_rtc_hookup);
+#endif
+
+static void
+mpc83xx_restart(char *cmd)
+{
+#define RST_OFFSET     0x00000900
+#define RST_PROT_REG   0x00000018
+#define RST_CTRL_REG   0x0000001c
+       __be32 __iomem *reg;
+
+       // map reset register space
+       reg = ioremap(get_immrbase() + 0x900, 0xff);
+
+       local_irq_disable();
+
+       /* enable software reset "RSTE" */
+       out_be32(reg + (RST_PROT_REG >> 2), 0x52535445);
+
+       /* set software hard reset */
+       out_be32(reg + (RST_CTRL_REG >> 2), 0x52535445);
+       for(;;);
+}
+
+static long __init
+mpc83xx_time_init(void)
+{
+#define SPCR_OFFSET    0x00000110
+#define SPCR_TBEN      0x00400000
+       __be32 __iomem *spcr = ioremap(get_immrbase() + SPCR_OFFSET, 4);
+       __be32 tmp;
+
+       tmp = in_be32(spcr);
+       out_be32(spcr, tmp|SPCR_TBEN);
+
+       iounmap(spcr);
+
+       return 0;
+}
+void __init
+platform_init(void)
+{
+       /* setup the PowerPC module struct */
+       ppc_md.setup_arch = mpc834x_sys_setup_arch;
+
+       ppc_md.init_IRQ = mpc834x_sys_init_IRQ;
+       ppc_md.get_irq = ipic_get_irq;
+
+       ppc_md.restart = mpc83xx_restart;
+
+       ppc_md.time_init = mpc83xx_time_init;
+       ppc_md.set_rtc_time = NULL;
+       ppc_md.get_rtc_time = NULL;
+       ppc_md.calibrate_decr = generic_calibrate_decr;
+
+       ppc_md.progress = udbg_progress;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mpc834x_sys_init(): exit", 0);
+
+       return;
+}
+
+
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h
new file mode 100644 (file)
index 0000000..e4ca39f
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * arch/powerppc/platforms/83xx/mpc834x_sys.h
+ *
+ * MPC834X SYS 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_SYS_H__
+#define __MACH_MPC83XX_SYS_H__
+
+#define PIRQA  MPC83xx_IRQ_EXT4
+#define PIRQB  MPC83xx_IRQ_EXT5
+#define PIRQC  MPC83xx_IRQ_EXT6
+#define PIRQD  MPC83xx_IRQ_EXT7
+
+#endif                /* __MACH_MPC83XX_SYS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
new file mode 100644 (file)
index 0000000..ce9e66a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __MPC83XX_H__
+#define __MPC83XX_H__
+
+#include <linux/init.h>
+#include <linux/device.h>
+
+/*
+ * Declaration for the various functions exported by the
+ * mpc83xx_* files. Mostly for use by mpc83xx_setup
+ */
+
+extern int add_bridge(struct device_node *dev);
+
+#endif /* __MPC83XX_H__ */
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
new file mode 100644 (file)
index 0000000..469cdac
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * FSL SoC setup code
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * 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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+int mpc83xx_pci2_busno;
+
+#ifdef CONFIG_PCI
+int __init add_bridge(struct device_node *dev)
+{
+       int len;
+       struct pci_controller *hose;
+       struct resource rsrc;
+       int *bus_range;
+       int primary = 1, has_address = 0;
+       phys_addr_t immr = get_immrbase();
+
+       DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+       /* Fetch host bridge registers address */
+       has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+
+       /* Get bus range if any */
+       bus_range = (int *) 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);
+       }
+
+       hose = pcibios_alloc_controller();
+       if (!hose)
+               return -ENOMEM;
+       hose->arch_data = dev;
+       hose->set_cfg_type = 1;
+
+       hose->first_busno = bus_range ? bus_range[0] : 0;
+       hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+       /* MPC83xx supports up to two host controllers one at 0x8500 from immrbar
+        * the other at 0x8600, we consider the 0x8500 the primary controller
+        */
+       /* PCI 1 */
+       if ((rsrc.start & 0xfffff) == 0x8500) {
+               setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304);
+       }
+       /* PCI 2*/
+       if ((rsrc.start & 0xfffff) == 0x8600) {
+               setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
+               primary = 0;
+               hose->bus_offset = hose->first_busno;
+               mpc83xx_pci2_busno = hose->first_busno;
+       }
+
+       printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%08lx. "
+              "Firmware bus number: %d->%d\n",
+               rsrc.start, hose->first_busno, hose->last_busno);
+
+       DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
+               hose, hose->cfg_addr, hose->cfg_data);
+
+       /* Interpret the "ranges" property */
+       /* This also maps the I/O region and sets isa_io/mem_base */
+       pci_process_bridge_OF_ranges(hose, dev, primary);
+
+       return 0;
+}
+
+#endif
index 82c429d487f3e6247a1079bc3bbb9e591e5e2ad8..00c52f27ef4f87f3d445eee09c6cd8d8fb916c3c 100644 (file)
@@ -135,12 +135,13 @@ int __init
 hydra_init(void)
 {
        struct device_node *np;
+       struct resource r;
 
        np = find_devices("mac-io");
-       if (np == NULL || np->n_addrs == 0)
+       if (np == NULL || of_address_to_resource(np, 0, &r))
                return 0;
-       Hydra = ioremap(np->addrs[0].address, np->addrs[0].size);
-       printk("Hydra Mac I/O at %lx\n", np->addrs[0].address);
+       Hydra = ioremap(r.start, r.end-r.start);
+       printk("Hydra Mac I/O at %lx\n", r.start);
        printk("Hydra Feature_Control was %x",
               in_le32(&Hydra->Feature_Control));
        out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN |
@@ -177,18 +178,24 @@ setup_python(struct pci_controller *hose, struct device_node *dev)
 {
        u32 __iomem *reg;
        u32 val;
-       unsigned long addr = dev->addrs[0].address;
+       struct resource r;
 
-       setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010);
+       if (of_address_to_resource(dev, 0, &r)) {
+               printk(KERN_ERR "No address for Python PCI controller\n");
+               return;
+       }
 
        /* Clear the magic go-slow bit */
-       reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40);
+       reg = ioremap(r.start + 0xf6000, 0x40);
+       BUG_ON(!reg); 
        val = in_be32(&reg[12]);
        if (val & PRG_CL_RESET_VALID) {
                out_be32(&reg[12], val & ~PRG_CL_RESET_VALID);
                in_be32(&reg[12]);
        }
        iounmap(reg);
+
+       setup_indirect_pci(hose, r.start + 0xf8000, r.start + 0xf8010);
 }
 
 /* Marvell Discovery II based Pegasos 2 */
@@ -218,7 +225,7 @@ chrp_find_bridges(void)
        char *model, *machine;
        int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
        struct device_node *root = find_path_device("/");
-
+       struct resource r;
        /*
         * The PCI host bridge nodes on some machines don't have
         * properties to adequately identify them, so we have to
@@ -238,7 +245,7 @@ chrp_find_bridges(void)
                        continue;
                ++index;
                /* The GG2 bridge on the LongTrail doesn't have an address */
-               if (dev->n_addrs < 1 && !is_longtrail) {
+               if (of_address_to_resource(dev, 0, &r) && !is_longtrail) {
                        printk(KERN_WARNING "Can't use %s: no address\n",
                               dev->full_name);
                        continue;
@@ -255,8 +262,8 @@ chrp_find_bridges(void)
                        printk(KERN_INFO "PCI buses %d..%d",
                               bus_range[0], bus_range[1]);
                printk(" controlled by %s", dev->type);
-               if (dev->n_addrs > 0)
-                       printk(" at %lx", dev->addrs[0].address);
+               if (!is_longtrail)
+                       printk(" at %lx", r.start);
                printk("\n");
 
                hose = pcibios_alloc_controller();
index 4ec8ba737e7d71cf486abf14d6f27d9d9e1ce317..2dc87aa5962fe8e1b264506bc7f00fef59897bd6 100644 (file)
@@ -352,9 +352,10 @@ static void __init chrp_find_openpic(void)
                opaddr = opprop[na-1];  /* assume 32-bit */
                oplen /= na * sizeof(unsigned int);
        } else {
-               if (np->n_addrs == 0)
+               struct resource r;
+               if (of_address_to_resource(np, 0, &r))
                        return;
-               opaddr = np->addrs[0].address;
+               opaddr = r.start;
                oplen = 0;
        }
 
@@ -377,7 +378,7 @@ static void __init chrp_find_openpic(void)
         */
        if (oplen < len) {
                printk(KERN_ERR "Insufficient addresses for distributed"
-                      " OpenPIC (%d < %d)\n", np->n_addrs, len);
+                      " OpenPIC (%d < %d)\n", oplen, len);
                len = oplen;
        }
 
index 737ee5d9f0aad5cdbbfd4746af9d39aae43aafb4..36a0f97bb7b13143dee6bf88cf1818bbb95f446f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/init.h>
 #include <linux/bcd.h>
+#include <linux/ioport.h>
 
 #include <asm/io.h>
 #include <asm/nvram.h>
@@ -37,14 +38,16 @@ static int nvram_data = NVRAM_DATA;
 long __init chrp_time_init(void)
 {
        struct device_node *rtcs;
+       struct resource r;
        int base;
 
        rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
        if (rtcs == NULL)
                rtcs = find_compatible_devices("rtc", "ds1385-rtc");
-       if (rtcs == NULL || rtcs->addrs == NULL)
+       if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r))
                return 0;
-       base = rtcs->addrs[0].address;
+       
+       base = r.start;
        nvram_as1 = 0;
        nvram_as0 = base;
        nvram_data = base + 1;
index 83442ea77476a88e31985b5ae331eb71edabc076..be3fbfc24e6cc2b1ecf947df77fd38f9c4f2b050 100644 (file)
@@ -334,14 +334,12 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
  */
 int iSeries_get_irq(struct pt_regs *regs)
 {
-       struct paca_struct *lpaca;
        /* -2 means ignore this interrupt */
        int irq = -2;
 
-       lpaca = get_paca();
 #ifdef CONFIG_SMP
-       if (lpaca->lppaca.int_dword.fields.ipi_cnt) {
-               lpaca->lppaca.int_dword.fields.ipi_cnt = 0;
+       if (get_lppaca()->int_dword.fields.ipi_cnt) {
+               get_lppaca()->int_dword.fields.ipi_cnt = 0;
                iSeries_smp_message_recv(regs);
        }
 #endif /* CONFIG_SMP */
index dfe7aa1ba098facedbd1294dd6d1a26c8616ef1a..7641fc7e550a0ec1603dabab9cc917a8dfecdb72 100644 (file)
@@ -44,7 +44,8 @@ _GLOBAL(local_irq_restore)
        /* Check pending interrupts */
        /*   A decrementer, IPI or PMC interrupt may have occurred
         *   while we were in the hypervisor (which enables) */
-       ld      r4,PACALPPACA+LPPACAANYINT(r13)
+       ld      r4,PACALPPACAPTR(r13)
+       ld      r4,LPPACAANYINT(r4)
        cmpdi   r4,0
        beqlr
 
index c6bbe5c25107f2ed2a6452d549a41568d31c8bed..3f8790146b00a7ae73e7f28b93f6c380b730a7d6 100644 (file)
@@ -538,7 +538,7 @@ static unsigned long __init build_iSeries_Memory_Map(void)
  */
 static void __init iSeries_setup_arch(void)
 {
-       if (get_paca()->lppaca.shared_proc) {
+       if (get_lppaca()->shared_proc) {
                ppc_md.idle_loop = iseries_shared_idle;
                printk(KERN_INFO "Using shared processor idle loop\n");
        } else {
@@ -647,7 +647,7 @@ static void yield_shared_processor(void)
         * The decrementer stops during the yield.  Force a fake decrementer
         * here and let the timer_interrupt code sort out the actual time.
         */
-       get_paca()->lppaca.int_dword.fields.decr_int = 1;
+       get_lppaca()->int_dword.fields.decr_int = 1;
        process_iSeries_events();
 }
 
@@ -883,7 +883,7 @@ void dt_cpus(struct iseries_flat_dt *dt)
        pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (paca[i].lppaca.dyn_proc_status >= 2)
+               if (lppaca[i].dyn_proc_status >= 2)
                        continue;
 
                snprintf(p, 32 - (p - buf), "@%d", i);
@@ -891,7 +891,7 @@ void dt_cpus(struct iseries_flat_dt *dt)
 
                dt_prop_str(dt, "device_type", "cpu");
 
-               index = paca[i].lppaca.dyn_hv_phys_proc_index;
+               index = lppaca[i].dyn_hv_phys_proc_index;
                d = &xIoHriProcessorVpd[index];
 
                dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
index fcb094ec6aec6efa082879088bf542399c43b23e..6f9d407a709f21334f1fd3be58cf2685174a2787 100644 (file)
@@ -91,7 +91,7 @@ static void smp_iSeries_kick_cpu(int nr)
        BUG_ON((nr < 0) || (nr >= NR_CPUS));
 
        /* Verify that our partition has a processor nr */
-       if (paca[nr].lppaca.dyn_proc_status >= 2)
+       if (lppaca[nr].dyn_proc_status >= 2)
                return;
 
        /* The processor is currently spinning, waiting
index f40451da037c00bd5bc6bc066c2dee90fd1212b0..7d4099a34f925763ee394d6cf96b2bf670cff766 100644 (file)
@@ -316,7 +316,6 @@ static int __init add_bridge(struct device_node *dev)
        char* disp_name;
        int *bus_range;
        int primary = 1;
-       struct property *of_prop;
 
        DBG("Adding PCI host bridge %s\n", dev->full_name);
 
index a1cb4d2367204ecd01b3df138f8ac9dd4f7d7f86..ec5c1e10c407253bc2e8b3ba0ea2f3b738f6d7aa 100644 (file)
 #define DBG(fmt...)
 #endif
 
+static unsigned long maple_find_nvram_base(void)
+{
+       struct device_node *rtcs;
+       unsigned long result = 0;
+
+       /* find NVRAM device */
+       rtcs = of_find_compatible_node(NULL, "nvram", "AMD8111");
+       if (rtcs) {
+               struct resource r;
+               if (of_address_to_resource(rtcs, 0, &r)) {
+                       printk(KERN_EMERG "Maple: Unable to translate NVRAM"
+                              " address\n");
+                       goto bail;
+               }
+               if (!(r.flags & IORESOURCE_IO)) {
+                       printk(KERN_EMERG "Maple: NVRAM address isn't PIO!\n");
+                       goto bail;
+               }
+               result = r.start;
+       } else
+               printk(KERN_EMERG "Maple: Unable to find NVRAM\n");
+ bail:
+       of_node_put(rtcs);
+       return result;
+}
+
 static void maple_restart(char *cmd)
 {
        unsigned int maple_nvram_base;
        unsigned int maple_nvram_offset;
        unsigned int maple_nvram_command;
-       struct device_node *rtcs;
+       struct device_node *sp;
 
-       /* find NVRAM device */
-       rtcs = find_compatible_devices("nvram", "AMD8111");
-       if (rtcs && rtcs->addrs) {
-               maple_nvram_base = rtcs->addrs[0].address;
-       } else {
-               printk(KERN_EMERG "Maple: Unable to find NVRAM\n");
-               printk(KERN_EMERG "Maple: Manual Restart Required\n");
-               return;
-       }
+       maple_nvram_base = maple_find_nvram_base();
+       if (maple_nvram_base == 0)
+               goto fail;
 
        /* find service processor device */
-       rtcs = find_devices("service-processor");
-       if (!rtcs) {
+       sp = of_find_node_by_name(NULL, "service-processor");
+       if (!sp) {
                printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
-               printk(KERN_EMERG "Maple: Manual Restart Required\n");
-               return;
+               goto fail;
        }
-       maple_nvram_offset = *(unsigned int*) get_property(rtcs,
+       maple_nvram_offset = *(unsigned int*) get_property(sp,
                        "restart-addr", NULL);
-       maple_nvram_command = *(unsigned int*) get_property(rtcs,
+       maple_nvram_command = *(unsigned int*) get_property(sp,
                        "restart-value", NULL);
+       of_node_put(sp);
 
        /* send command */
        outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset);
        for (;;) ;
+ fail:
+       printk(KERN_EMERG "Maple: Manual Restart Required\n");
 }
 
 static void maple_power_off(void)
@@ -110,33 +132,29 @@ static void maple_power_off(void)
        unsigned int maple_nvram_base;
        unsigned int maple_nvram_offset;
        unsigned int maple_nvram_command;
-       struct device_node *rtcs;
+       struct device_node *sp;
 
-       /* find NVRAM device */
-       rtcs = find_compatible_devices("nvram", "AMD8111");
-       if (rtcs && rtcs->addrs) {
-               maple_nvram_base = rtcs->addrs[0].address;
-       } else {
-               printk(KERN_EMERG "Maple: Unable to find NVRAM\n");
-               printk(KERN_EMERG "Maple: Manual Power-Down Required\n");
-               return;
-       }
+       maple_nvram_base = maple_find_nvram_base();
+       if (maple_nvram_base == 0)
+               goto fail;
 
        /* find service processor device */
-       rtcs = find_devices("service-processor");
-       if (!rtcs) {
+       sp = of_find_node_by_name(NULL, "service-processor");
+       if (!sp) {
                printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
-               printk(KERN_EMERG "Maple: Manual Power-Down Required\n");
-               return;
+               goto fail;
        }
-       maple_nvram_offset = *(unsigned int*) get_property(rtcs,
+       maple_nvram_offset = *(unsigned int*) get_property(sp,
                        "power-off-addr", NULL);
-       maple_nvram_command = *(unsigned int*) get_property(rtcs,
+       maple_nvram_command = *(unsigned int*) get_property(sp,
                        "power-off-value", NULL);
+       of_node_put(sp);
 
        /* send command */
        outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset);
        for (;;) ;
+ fail:
+       printk(KERN_EMERG "Maple: Manual Power-Down Required\n");
 }
 
 static void maple_halt(void)
@@ -179,9 +197,6 @@ void __init maple_setup_arch(void)
  */
 static void __init maple_init_early(void)
 {
-       unsigned int default_speed;
-       u64 physport;
-
        DBG(" -> maple_init_early\n");
 
        /* Initialize hash table, from now on, we can take hash faults
index 15846cc938acd4a87158a47b19ba547f5af062d5..50bc4eb853535bca3e78eae519dbf98367b7f294 100644 (file)
@@ -168,11 +168,24 @@ unsigned long __init maple_get_boot_time(void)
        struct rtc_time tm;
        struct device_node *rtcs;
 
-       rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
-       if (rtcs && rtcs->addrs) {
-               maple_rtc_addr = rtcs->addrs[0].address;
-               printk(KERN_INFO "Maple: Found RTC at 0x%x\n", maple_rtc_addr);
-       } else {
+       rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00");
+       if (rtcs) {
+               struct resource r;
+               if (of_address_to_resource(rtcs, 0, &r)) {
+                       printk(KERN_EMERG "Maple: Unable to translate RTC"
+                              " address\n");
+                       goto bail;
+               }
+               if (!(r.flags & IORESOURCE_IO)) {
+                       printk(KERN_EMERG "Maple: RTC address isn't PIO!\n");
+                       goto bail;
+               }
+               maple_rtc_addr = r.start;
+               printk(KERN_INFO "Maple: Found RTC at IO 0x%x\n",
+                      maple_rtc_addr);
+       }
+ bail:
+       if (maple_rtc_addr == 0) {
                maple_rtc_addr = RTC_PORT(0); /* legacy address */
                printk(KERN_INFO "Maple: No device node for RTC, assuming "
                       "legacy address (0x%x)\n", maple_rtc_addr);
index 1fe445ab78a6342f0efed8e96349045d5a33eec2..8952528d31ac61ed7801c77d771dd6c00ec8b507 100644 (file)
@@ -254,11 +254,11 @@ out:
 void vpa_init(int cpu)
 {
        int hwcpu = get_hard_smp_processor_id(cpu);
-       unsigned long vpa = __pa(&paca[cpu].lppaca);
+       unsigned long vpa = __pa(&lppaca[cpu]);
        long ret;
 
        if (cpu_has_feature(CPU_FTR_ALTIVEC))
-               paca[cpu].lppaca.vmxregs_in_use = 1;
+               lppaca[cpu].vmxregs_in_use = 1;
 
        ret = register_vpa(hwcpu, vpa);
 
index d8864164dbe809c85c012fe03957e96d4b398ff4..86cfa6ecdcf3b55ae6e2468400650258d48e4231 100644 (file)
@@ -350,6 +350,100 @@ static int do_remove_node(char *buf)
        return rv;
 }
 
+static char *parse_node(char *buf, size_t bufsize, struct device_node **npp)
+{
+       char *handle_str;
+       phandle handle;
+       *npp = NULL;
+
+       handle_str = buf;
+
+       buf = strchr(buf, ' ');
+       if (!buf)
+               return NULL;
+       *buf = '\0';
+       buf++;
+
+       handle = simple_strtoul(handle_str, NULL, 10);
+
+       *npp = of_find_node_by_phandle(handle);
+       return buf;
+}
+
+static int do_add_property(char *buf, size_t bufsize)
+{
+       struct property *prop = NULL;
+       struct device_node *np;
+       unsigned char *value;
+       char *name, *end;
+       int length;
+       end = buf + bufsize;
+       buf = parse_node(buf, bufsize, &np);
+
+       if (!np)
+               return -ENODEV;
+
+       if (parse_next_property(buf, end, &name, &length, &value) == NULL)
+               return -EINVAL;
+
+       prop = new_property(name, length, value, NULL);
+       if (!prop)
+               return -ENOMEM;
+
+       prom_add_property(np, prop);
+
+       return 0;
+}
+
+static int do_remove_property(char *buf, size_t bufsize)
+{
+       struct device_node *np;
+       char *tmp;
+       struct property *prop;
+       buf = parse_node(buf, bufsize, &np);
+
+       if (!np)
+               return -ENODEV;
+
+       tmp = strchr(buf,' ');
+       if (tmp)
+               *tmp = '\0';
+
+       if (strlen(buf) == 0)
+               return -EINVAL;
+
+       prop = of_find_property(np, buf, NULL);
+
+       return prom_remove_property(np, prop);
+}
+
+static int do_update_property(char *buf, size_t bufsize)
+{
+       struct device_node *np;
+       unsigned char *value;
+       char *name, *end;
+       int length;
+       struct property *newprop, *oldprop;
+       buf = parse_node(buf, bufsize, &np);
+       end = buf + bufsize;
+
+       if (!np)
+               return -ENODEV;
+
+       if (parse_next_property(buf, end, &name, &length, &value) == NULL)
+               return -EINVAL;
+
+       newprop = new_property(name, length, value, NULL);
+       if (!newprop)
+               return -ENOMEM;
+
+       oldprop = of_find_property(np, name,NULL);
+       if (!oldprop)
+               return -ENODEV;
+
+       return prom_update_property(np, newprop, oldprop);
+}
+
 /**
  * ofdt_write - perform operations on the Open Firmware device tree
  *
@@ -392,6 +486,12 @@ static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t coun
                rv = do_add_node(tmp, count - (tmp - kbuf));
        else if (!strcmp(kbuf, "remove_node"))
                rv = do_remove_node(tmp);
+       else if (!strcmp(kbuf, "add_property"))
+               rv = do_add_property(tmp, count - (tmp - kbuf));
+       else if (!strcmp(kbuf, "remove_property"))
+               rv = do_remove_property(tmp, count - (tmp - kbuf));
+       else if (!strcmp(kbuf, "update_property"))
+               rv = do_update_property(tmp, count - (tmp - kbuf));
        else
                rv = -EINVAL;
 out:
index 68b7f086d63dbef9f278bd0110cd21e31329b0ee..da6cebaf72cda275fc1b9bb7613b7fe3efa97cbb 100644 (file)
@@ -190,7 +190,7 @@ static void pseries_lpar_enable_pmcs(void)
 
        /* instruct hypervisor to maintain PMCs */
        if (firmware_has_feature(FW_FEATURE_SPLPAR))
-               get_paca()->lppaca.pmcregs_in_use = 1;
+               get_lppaca()->pmcregs_in_use = 1;
 }
 
 static void __init pSeries_setup_arch(void)
@@ -234,7 +234,7 @@ static void __init pSeries_setup_arch(void)
        /* Choose an idle loop */
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                vpa_init(boot_cpuid);
-               if (get_paca()->lppaca.shared_proc) {
+               if (get_lppaca()->shared_proc) {
                        printk(KERN_INFO "Using shared processor idle loop\n");
                        ppc_md.idle_loop = pseries_shared_idle;
                } else {
@@ -444,10 +444,10 @@ DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
 
 static inline void dedicated_idle_sleep(unsigned int cpu)
 {
-       struct paca_struct *ppaca = &paca[cpu ^ 1];
+       struct lppaca *plppaca = &lppaca[cpu ^ 1];
 
        /* Only sleep if the other thread is not idle */
-       if (!(ppaca->lppaca.idle)) {
+       if (!(plppaca->idle)) {
                local_irq_disable();
 
                /*
@@ -480,7 +480,6 @@ static inline void dedicated_idle_sleep(unsigned int cpu)
 
 static void pseries_dedicated_idle(void)
 { 
-       struct paca_struct *lpaca = get_paca();
        unsigned int cpu = smp_processor_id();
        unsigned long start_snooze;
        unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
@@ -491,7 +490,7 @@ static void pseries_dedicated_idle(void)
                 * Indicate to the HV that we are idle. Now would be
                 * a good time to find other work to dispatch.
                 */
-               lpaca->lppaca.idle = 1;
+               get_lppaca()->idle = 1;
 
                if (!need_resched()) {
                        start_snooze = get_tb() +
@@ -518,7 +517,7 @@ static void pseries_dedicated_idle(void)
                        HMT_medium();
                }
 
-               lpaca->lppaca.idle = 0;
+               get_lppaca()->idle = 0;
                ppc64_runlatch_on();
 
                preempt_enable_no_resched();
@@ -532,7 +531,6 @@ static void pseries_dedicated_idle(void)
 
 static void pseries_shared_idle(void)
 {
-       struct paca_struct *lpaca = get_paca();
        unsigned int cpu = smp_processor_id();
 
        while (1) {
@@ -540,7 +538,7 @@ static void pseries_shared_idle(void)
                 * Indicate to the HV that we are idle. Now would be
                 * a good time to find other work to dispatch.
                 */
-               lpaca->lppaca.idle = 1;
+               get_lppaca()->idle = 1;
 
                while (!need_resched() && !cpu_is_offline(cpu)) {
                        local_irq_disable();
@@ -564,7 +562,7 @@ static void pseries_shared_idle(void)
                        HMT_medium();
                }
 
-               lpaca->lppaca.idle = 0;
+               get_lppaca()->idle = 0;
                ppc64_runlatch_on();
 
                preempt_enable_no_resched();
@@ -588,7 +586,7 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
 {
        /* Don't risk a hypervisor call if we're crashing */
        if (!crash_shutdown) {
-               unsigned long vpa = __pa(&get_paca()->lppaca);
+               unsigned long vpa = __pa(get_lppaca());
 
                if (unregister_vpa(hard_smp_processor_id(), vpa)) {
                        printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
index 0ae841347a099d4b1714079ed436993914ad8c59..4c2b356774eada42c083c1796c0f7eec93927088 100644 (file)
@@ -7,3 +7,4 @@ obj-$(CONFIG_40x)               += dcr.o
 obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
 obj-$(CONFIG_PPC_83xx)         += ipic.o
+obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
new file mode 100644 (file)
index 0000000..064c9de
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * FSL SoC setup code
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * 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/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+#include <mm/mmu_decl.h>
+
+static phys_addr_t immrbase = -1;
+
+phys_addr_t get_immrbase(void)
+{
+       struct device_node *soc;
+
+       if (immrbase != -1)
+               return immrbase;
+
+       soc = of_find_node_by_type(NULL, "soc");
+       if (soc != 0) {
+               unsigned int size;
+               void *prop = get_property(soc, "reg", &size);
+               immrbase = of_translate_address(soc, prop);
+               of_node_put(soc);
+       };
+
+       return immrbase;
+}
+EXPORT_SYMBOL(get_immrbase);
+
+static const char * gfar_tx_intr = "tx";
+static const char * gfar_rx_intr = "rx";
+static const char * gfar_err_intr = "error";
+
+static int __init gfar_of_init(void)
+{
+       struct device_node *np;
+       unsigned int i;
+       struct platform_device *mdio_dev, *gfar_dev;
+       struct resource res;
+       int ret;
+
+       for (np = NULL, i = 0; (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; i++) {
+               int k;
+               struct device_node *child = NULL;
+               struct gianfar_mdio_data mdio_data;
+
+               memset(&res, 0, sizeof(res));
+               memset(&mdio_data, 0, sizeof(mdio_data));
+
+               ret = of_address_to_resource(np, 0, &res);
+               if (ret)
+                       goto mdio_err;
+
+               mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", res.start, &res, 1);
+               if (IS_ERR(mdio_dev)) {
+                       ret = PTR_ERR(mdio_dev);
+                       goto mdio_err;
+               }
+
+               for (k = 0; k < 32; k++)
+                       mdio_data.irq[k] = -1;
+
+               while ((child = of_get_next_child(np, child)) != NULL) {
+                       if (child->n_intrs) {
+                               u32 *id = (u32 *) get_property(child, "reg", NULL);
+                               mdio_data.irq[*id] = child->intrs[0].line;
+                       }
+               }
+
+               ret = platform_device_add_data(mdio_dev, &mdio_data, sizeof(struct gianfar_mdio_data));
+               if (ret)
+                       goto mdio_unreg;
+       }
+
+       for (np = NULL, i = 0; (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; i++) {
+               struct resource r[4];
+               struct device_node *phy, *mdio;
+               struct gianfar_platform_data gfar_data;
+               unsigned int *id;
+               char *model;
+               void *mac_addr;
+               phandle *ph;
+
+               memset(r, 0, sizeof(r));
+               memset(&gfar_data, 0, sizeof(gfar_data));
+
+               ret = of_address_to_resource(np, 0, &r[0]);
+               if (ret)
+                       goto gfar_err;
+
+               r[1].start = np->intrs[0].line;
+               r[1].end = np->intrs[0].line;
+               r[1].flags = IORESOURCE_IRQ;
+
+               model = get_property(np, "model", NULL);
+
+               /* If we aren't the FEC we have multiple interrupts */
+               if (model && strcasecmp(model, "FEC")) {
+                       r[1].name = gfar_tx_intr;
+
+                       r[2].name = gfar_rx_intr;
+                       r[2].start = np->intrs[1].line;
+                       r[2].end = np->intrs[1].line;
+                       r[2].flags = IORESOURCE_IRQ;
+
+                       r[3].name = gfar_err_intr;
+                       r[3].start = np->intrs[2].line;
+                       r[3].end = np->intrs[2].line;
+                       r[3].flags = IORESOURCE_IRQ;
+               }
+
+               gfar_dev = platform_device_register_simple("fsl-gianfar", i, &r[0], np->n_intrs + 1);
+
+               if (IS_ERR(gfar_dev)) {
+                       ret = PTR_ERR(gfar_dev);
+                       goto gfar_err;
+               }
+
+               mac_addr = get_property(np, "address", NULL);
+               memcpy(gfar_data.mac_addr, mac_addr, 6);
+
+               if (model && !strcasecmp(model, "TSEC"))
+                       gfar_data.device_flags =
+                               FSL_GIANFAR_DEV_HAS_GIGABIT |
+                               FSL_GIANFAR_DEV_HAS_COALESCE |
+                               FSL_GIANFAR_DEV_HAS_RMON |
+                               FSL_GIANFAR_DEV_HAS_MULTI_INTR;
+               if (model && !strcasecmp(model, "eTSEC"))
+                       gfar_data.device_flags =
+                               FSL_GIANFAR_DEV_HAS_GIGABIT |
+                               FSL_GIANFAR_DEV_HAS_COALESCE |
+                               FSL_GIANFAR_DEV_HAS_RMON |
+                               FSL_GIANFAR_DEV_HAS_MULTI_INTR |
+                               FSL_GIANFAR_DEV_HAS_CSUM |
+                               FSL_GIANFAR_DEV_HAS_VLAN |
+                               FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+
+               ph = (phandle *) get_property(np, "phy-handle", NULL);
+               phy = of_find_node_by_phandle(*ph);
+
+               if (phy == NULL) {
+                       ret = -ENODEV;
+                       goto gfar_unreg;
+               }
+
+               mdio = of_get_parent(phy);
+
+               id = (u32 *) get_property(phy, "reg", NULL);
+               ret = of_address_to_resource(mdio, 0, &res);
+               if (ret) {
+                       of_node_put(phy);
+                       of_node_put(mdio);
+                       goto gfar_unreg;
+               }
+
+               gfar_data.phy_id = *id;
+               gfar_data.bus_id = res.start;
+
+               of_node_put(phy);
+               of_node_put(mdio);
+
+               ret = platform_device_add_data(gfar_dev, &gfar_data, sizeof(struct gianfar_platform_data));
+               if (ret)
+                       goto gfar_unreg;
+       }
+
+       return 0;
+
+mdio_unreg:
+       platform_device_unregister(mdio_dev);
+mdio_err:
+       return ret;
+
+gfar_unreg:
+       platform_device_unregister(gfar_dev);
+gfar_err:
+       return ret;
+}
+arch_initcall(gfar_of_init);
+
+static int __init fsl_i2c_of_init(void)
+{
+       struct device_node *np;
+       unsigned int i;
+       struct platform_device *i2c_dev;
+       int ret;
+
+       for (np = NULL, i = 0; (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; i++) {
+               struct resource r[2];
+               struct fsl_i2c_platform_data i2c_data;
+               unsigned char * flags = NULL;
+
+               memset(&r, 0, sizeof(r));
+               memset(&i2c_data, 0, sizeof(i2c_data));
+
+               ret = of_address_to_resource(np, 0, &r[0]);
+               if (ret)
+                       goto i2c_err;
+
+               r[1].start = np->intrs[0].line;
+               r[1].end = np->intrs[0].line;
+               r[1].flags = IORESOURCE_IRQ;
+
+               i2c_dev = platform_device_register_simple("fsl-i2c", i, r, 2);
+               if (IS_ERR(i2c_dev)) {
+                       ret = PTR_ERR(i2c_dev);
+                       goto i2c_err;
+               }
+
+               i2c_data.device_flags = 0;
+               flags = get_property(np, "dfsrr", NULL);
+               if (flags)
+                       i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
+
+               flags = get_property(np, "fsl5200-clocking", NULL);
+               if (flags)
+                       i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
+
+               ret = platform_device_add_data(i2c_dev, &i2c_data, sizeof(struct fsl_i2c_platform_data));
+               if (ret)
+                       goto i2c_unreg;
+       }
+
+       return 0;
+
+i2c_unreg:
+       platform_device_unregister(i2c_dev);
+i2c_err:
+       return ret;
+}
+arch_initcall(fsl_i2c_of_init);
+
+#ifdef CONFIG_PPC_83xx
+static int __init mpc83xx_wdt_init(void)
+{
+       struct resource r;
+       struct device_node *soc, *np;
+       struct platform_device *dev;
+       unsigned int *freq;
+       int ret;
+
+       np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
+
+       if (!np) {
+               ret = -ENODEV;
+               goto mpc83xx_wdt_nodev;
+       }
+
+       soc = of_find_node_by_type(NULL, "soc");
+
+       if (!soc) {
+               ret = -ENODEV;
+               goto mpc83xx_wdt_nosoc;
+       }
+
+       freq = (unsigned int *)get_property(soc, "bus-frequency", NULL);
+       if (!freq) {
+               ret = -ENODEV;
+               goto mpc83xx_wdt_err;
+       }
+
+       memset(&r, 0, sizeof(r));
+
+       ret = of_address_to_resource(np, 0, &r);
+       if (ret)
+               goto mpc83xx_wdt_err;
+
+       dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
+       if (IS_ERR(dev)) {
+               ret = PTR_ERR(dev);
+               goto mpc83xx_wdt_err;
+       }
+
+       ret = platform_device_add_data(dev, freq, sizeof(int));
+       if (ret)
+               goto mpc83xx_wdt_unreg;
+
+       of_node_put(soc);
+       of_node_put(np);
+
+       return 0;
+
+mpc83xx_wdt_unreg:
+       platform_device_unregister(dev);
+mpc83xx_wdt_err:
+       of_node_put(soc);
+mpc83xx_wdt_nosoc:
+       of_node_put(np);
+mpc83xx_wdt_nodev:
+       return ret;
+}
+arch_initcall(mpc83xx_wdt_init);
+#endif
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
new file mode 100644 (file)
index 0000000..c433d3f
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __PPC_FSL_SOC_H
+#define __PPC_FSL_SOC_H
+#ifdef __KERNEL__
+
+extern phys_addr_t get_immrbase(void);
+
+#endif
+#endif
index ebc4db8fcc63de0380e2dacc99b5feb5a9abe263..8ace2a1f3b488f1c3b3dcfbf1b2a22da613e395b 100644 (file)
@@ -215,7 +215,6 @@ static struct tty_driver *siccnormal_driver;
  * memory if large numbers of serial ports are open.
  */
 static u_char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 #define HIGH_BITS_OFFSET    ((sizeof(long)-sizeof(int))*8)
 
index d65810108bc35dbdaf2f58a3a0c496baceb087e3..11899f06bf06b4657d1a6983d68867013acc577c 100644 (file)
@@ -58,11 +58,11 @@ config 6xx
        help
          There are four types of PowerPC chips supported.  The more common
          types (601, 603, 604, 740, 750, 7400), the Motorola embedded
-         versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the IBM embedded
-         versions (403 and 405) and the high end 64 bit Power processors
-         (POWER 3, POWER4, and IBM 970 also known as G5)
+         versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the IBM
+         embedded versions (403 and 405) and the POWER3 processor.
+         (For support for more recent 64-bit processors, set ARCH=powerpc.)
          Unless you are building a kernel for one of the embedded processor
-         systems, 64 bit IBM RS/6000 or an Apple G5, choose 6xx.
+         systems or a POWER3-based IBM RS/6000, choose 6xx.
          Note that the kernel runs in 32-bit mode even on 64-bit chips.
          Also note that because the 52xx, 82xx, & 83xx family has a 603e core,
          specific support for that chipset is asked later on.
@@ -77,10 +77,6 @@ config POWER3
        select PPC_FPU
        bool "POWER3"
 
-config POWER4
-       select PPC_FPU
-       bool "POWER4 and 970 (G5)"
-
 config 8xx
        bool "8xx"
 
@@ -123,7 +119,7 @@ config PHYS_64BIT
 
 config ALTIVEC
        bool "AltiVec Support"
-       depends on 6xx || POWER4
+       depends on 6xx
        depends on !8260 && !83xx
        ---help---
          This option enables kernel support for the Altivec extensions to the
@@ -235,18 +231,9 @@ config KEXEC
 
 source "drivers/cpufreq/Kconfig"
 
-config CPU_FREQ_PMAC
-       bool "Support for Apple PowerBooks"
-       depends on CPU_FREQ && ADB_PMU
-       select CPU_FREQ_TABLE
-       help
-         This adds support for frequency switching on Apple PowerBooks,
-         this currently includes some models of iBook & Titanium
-         PowerBook.
-
 config PPC601_SYNC_FIX
        bool "Workarounds for PPC601 bugs"
-       depends on 6xx && (PPC_PREP || PPC_PMAC)
+       depends on 6xx && PPC_PREP
        help
          Some versions of the PPC601 (the first PowerPC chip) have bugs which
          mean that extra synchronization instructions are required near
@@ -258,26 +245,17 @@ config PPC601_SYNC_FIX
 
          If in doubt, say Y here.
 
-config HOTPLUG_CPU
-       bool "Support for enabling/disabling CPUs"
-       depends on SMP && HOTPLUG && EXPERIMENTAL && PPC_PMAC
-       ---help---
-         Say Y here to be able to disable and re-enable individual
-         CPUs at runtime on SMP machines.
-
-         Say N if you are unsure.
-
 source arch/ppc/platforms/4xx/Kconfig
 source arch/ppc/platforms/85xx/Kconfig
 
 config PPC64BRIDGE
        bool
-       depends on POWER3 || POWER4
+       depends on POWER3
        default y
 
 config PPC_STD_MMU
        bool
-       depends on 6xx || POWER3 || POWER4
+       depends on 6xx || POWER3
        default y
 
 config NOT_COHERENT_CACHE
@@ -505,7 +483,7 @@ endchoice
 
 choice
        prompt "Machine Type"
-       depends on 6xx || POWER3 || POWER4
+       depends on 6xx || POWER3
        default PPC_MULTIPLATFORM
        ---help---
          Linux currently supports several different kinds of PowerPC-based
@@ -516,11 +494,15 @@ choice
          Platform) machines (including all of the recent IBM RS/6000 and
          pSeries machines), and several embedded PowerPC systems containing
          4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors.  Currently, the
-         default option is to build a kernel which works on the first three.
+         default option is to build a kernel which works on PReP and CHRP.
 
-         Select CHRP/PowerMac/PReP if configuring for an IBM RS/6000 or
-         pSeries machine, a Power Macintosh (including iMacs, iBooks and
-         Powerbooks), or a PReP machine.
+         Note that support for Apple machines is now only available with
+         ARCH=powerpc, and has been removed from this menu.  If you wish
+         to build a kernel for an Apple machine, exit this configuration
+         process and re-run it with ARCH=powerpc.
+
+         Select CHRP/PReP if configuring for an IBM RS/6000 or
+         pSeries machine, or a PReP machine.
 
          Select Gemini if configuring for a Synergy Microsystems' Gemini
          series Single Board Computer.  More information is available at:
@@ -530,7 +512,7 @@ choice
          available at: <http://linux-apus.sourceforge.net/>.
 
 config PPC_MULTIPLATFORM
-       bool "CHRP/PowerMac/PReP"
+       bool "CHRP/PReP"
 
 config APUS
        bool "Amiga-APUS"
@@ -768,25 +750,14 @@ config CPM2
          on it (826x, 827x, 8560).
 
 config PPC_CHRP
-       bool
+       bool "Support for CHRP (Common Hardware Reference Platform) machines"
        depends on PPC_MULTIPLATFORM
        select PPC_I8259
        select PPC_INDIRECT_PCI
        default y
 
-config PPC_PMAC
-       bool
-       depends on PPC_MULTIPLATFORM
-       select PPC_INDIRECT_PCI
-       default y
-
-config PPC_PMAC64
-       bool
-       depends on PPC_PMAC && POWER4
-       default y
-
 config PPC_PREP
-       bool
+       bool "Support for PReP (PowerPC Reference Platform) machines"
        depends on PPC_MULTIPLATFORM
        select PPC_I8259
        select PPC_INDIRECT_PCI
@@ -794,7 +765,7 @@ config PPC_PREP
 
 config PPC_OF
        bool
-       depends on PPC_PMAC || PPC_CHRP
+       depends on PPC_CHRP
        default y
 
 config PPC_GEN550
@@ -1166,7 +1137,7 @@ config ISA
 
 config GENERIC_ISA_DMA
        bool
-       depends on POWER3 || POWER4 || 6xx && !CPM2
+       depends on POWER3 || 6xx && !CPM2
        default y
 
 config PPC_I8259
index 995f89bb049c2a8a0302e27f9deab3a0040d3860..efd8ce515d5fb332e8afacfabc60b958b2e55c05 100644 (file)
@@ -18,7 +18,7 @@ BOOT_TARGETS  = zImage zImage.initrd znetboot znetboot.initrd
 bootdir-y                      := simple
 bootdir-$(CONFIG_PPC_OF)       += openfirmware
 subdir-y                       := lib common images
-subdir-$(CONFIG_PPC_OF)                += of1275
+subdir-$(CONFIG_PPC_MULTIPLATFORM)     += of1275
 
 # for cleaning
 subdir-                                += simple openfirmware
index 83a6433459ce1fe487b10272c8fbf82ec04bc9f0..2a411ec2e650601c0e9fcb8d226b98e5c2a9b371 100644 (file)
@@ -21,26 +21,16 @@ bootlib     := $(boot)/lib
 of1275 := $(boot)/of1275
 images := $(boot)/images
 
-OBJCOPY_ARGS   := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
-COFF_LD_ARGS   := -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00500000 \
-                       -Bstatic
 CHRP_LD_ARGS   := -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00800000
-NEWWORLD_LD_ARGS:= -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x01000000
 
 COMMONOBJS     := start.o misc.o common.o
-COFFOBJS       := coffcrt0.o $(COMMONOBJS) coffmain.o
 CHRPOBJS       := crt0.o     $(COMMONOBJS) chrpmain.o
-NEWWORLDOBJS   := crt0.o     $(COMMONOBJS) newworldmain.o
 
-targets        := $(COFFOBJS) $(CHRPOBJS) $(NEWWORLDOBJS) dummy.o
-COFFOBJS       := $(addprefix $(obj)/, $(COFFOBJS))
+targets        := $(CHRPOBJS) dummy.o
 CHRPOBJS       := $(addprefix $(obj)/, $(CHRPOBJS))
-NEWWORLDOBJS   := $(addprefix $(obj)/, $(NEWWORLDOBJS))
 
 LIBS           := lib/lib.a $(bootlib)/lib.a $(of1275)/lib.a $(common)/lib.a
 
-HACKCOFF := $(utils)/hack-coff
-
 ifdef CONFIG_SMP
 END := .smp
 endif
@@ -72,56 +62,11 @@ targets += image.initrd.o
 $(obj)/image.initrd.o: $(obj)/image.o $(images)/ramdisk.image.gz FORCE
        $(call if_changed,genimage-initrd)
 
-# Create the note section for New-World PowerMacs.
-quiet_cmd_mknote = MKNOTE  $@
-     cmd_mknote  = $(utils)/mknote > $@
-targets                += note
-$(obj)/note: $(utils)/mknote FORCE
-       $(call if_changed,mknote)
-
 
-$(obj)/coffcrt0.o: EXTRA_AFLAGS := -DXCOFF
-targets += coffcrt0.o crt0.o
-$(obj)/coffcrt0.o $(obj)/crt0.o: $(common)/crt0.S FORCE
+targets += crt0.o
+$(obj)/crt0.o: $(common)/crt0.S FORCE
        $(call if_changed_dep,as_o_S)
 
-quiet_cmd_gencoffb = COFF    $@
-      cmd_gencoffb = $(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) $< $(LIBS) && \
-                     $(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec)
-targets += coffboot
-$(obj)/coffboot: $(obj)/image.o $(COFFOBJS) $(LIBS) $(srctree)/$(boot)/ld.script FORCE
-       $(call if_changed,gencoffb)
-targets += coffboot.initrd
-$(obj)/coffboot.initrd: $(obj)/image.initrd.o $(COFFOBJS) $(LIBS) \
-                       $(srctree)/$(boot)/ld.script FORCE
-       $(call if_changed,gencoffb)
-
-
-quiet_cmd_gen-coff = COFF    $@
-      cmd_gen-coff = $(OBJCOPY) $(OBJCOPY_ARGS) $< $@ && \
-                       $(HACKCOFF) $@ && \
-                       ln -sf $(notdir $@) $(images)/zImage$(initrd).pmac
-
-$(images)/vmlinux.coff: $(obj)/coffboot
-       $(call cmd,gen-coff)
-
-$(images)/vmlinux.initrd.coff: $(obj)/coffboot.initrd
-       $(call cmd,gen-coff)
-
-quiet_cmd_gen-elf-pmac = ELF     $@
-      cmd_gen-elf-pmac = $(LD) $(NEWWORLD_LD_ARGS) -o $@ \
-                               $(NEWWORLDOBJS) $(LIBS) $< && \
-                       $(OBJCOPY) $@ $@ --add-section=.note=$(obj)/note \
-                                        -R .comment $(del-ramdisk-sec)
-
-$(images)/vmlinux.elf-pmac: $(obj)/image.o $(NEWWORLDOBJS) $(LIBS) \
-                       $(obj)/note $(srctree)/$(boot)/ld.script
-       $(call cmd,gen-elf-pmac)
-$(images)/vmlinux.initrd.elf-pmac: $(obj)/image.initrd.o $(NEWWORLDOBJS) \
-                                  $(LIBS) $(obj)/note \
-                                  $(srctree)/$(boot)/ld.script
-       $(call cmd,gen-elf-pmac)
-
 quiet_cmd_gen-chrp = CHRP    $@
       cmd_gen-chrp = $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) $< $(LIBS) && \
                        $(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec)
@@ -139,46 +84,23 @@ $(images)/zImage.chrp-rs6k $(images)/zImage.initrd.chrp-rs6k: \
        %-rs6k: %
        $(call cmd,addnote)
 
-quiet_cmd_gen-miboot = GEN     $@
-      cmd_gen-miboot = $(OBJCOPY) $(OBJCOPY_ARGS) \
-                      --add-section=$1=$(word 2, $^) $< $@
-$(images)/miboot.image: $(obj)/dummy.o $(images)/vmlinux.gz
-       $(call cmd,gen-miboot,image)
-
-$(images)/miboot.initrd.image: $(images)/miboot.image $(images)/ramdisk.image.gz
-       $(call cmd,gen-miboot,initrd)
-
 # The targets used on the make command-line
 
 .PHONY: zImage zImage.initrd
-zImage:                 $(images)/vmlinux.coff         \
-                $(images)/vmlinux.elf-pmac     \
-                $(images)/zImage.chrp          \
-                $(images)/zImage.chrp-rs6k     \
-                $(images)/miboot.image
+zImage:                 $(images)/zImage.chrp          \
+                $(images)/zImage.chrp-rs6k
        @echo '  kernel: $@ is ready ($<)'
-zImage.initrd:  $(images)/vmlinux.initrd.coff          \
-                $(images)/vmlinux.initrd.elf-pmac      \
-                $(images)/zImage.initrd.chrp           \
-                $(images)/zImage.initrd.chrp-rs6k      \
-                $(images)/miboot.initrd.image
+zImage.initrd:  $(images)/zImage.initrd.chrp           \
+                $(images)/zImage.initrd.chrp-rs6k
        @echo '  kernel: $@ is ready ($<)'
 
 TFTPIMAGE      := /tftpboot/zImage
 
 .PHONY: znetboot znetboot.initrd
-znetboot:      $(images)/vmlinux.coff          \
-               $(images)/vmlinux.elf-pmac      \
-               $(images)/zImage.chrp
-       cp $(images)/vmlinux.coff     $(TFTPIMAGE).pmac$(END)
-       cp $(images)/vmlinux.elf-pmac $(TFTPIMAGE).pmac$(END).elf
+znetboot:      $(images)/zImage.chrp
        cp $(images)/zImage.chrp      $(TFTPIMAGE).chrp$(END)
        @echo '  kernel: $@ is ready ($<)'
-znetboot.initrd:$(images)/vmlinux.initrd.coff          \
-               $(images)/vmlinux.initrd.elf-pmac       \
-               $(images)/zImage.initrd.chrp
-       cp $(images)/vmlinux.initrd.coff     $(TFTPIMAGE).pmac$(END)
-       cp $(images)/vmlinux.initrd.elf-pmac $(TFTPIMAGE).pmac$(END).elf
+znetboot.initrd:$(images)/zImage.initrd.chrp
        cp $(images)/zImage.initrd.chrp      $(TFTPIMAGE).chrp$(END)
        @echo '  kernel: $@ is ready ($<)'
 
diff --git a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c
deleted file mode 100644 (file)
index 2da8855..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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 <linux/string.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-
-#include "nonstdio.h"
-#include "of1275.h"
-
-/* Passed from the linker */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin[], __ramdisk_end;
-extern char _start, _end;
-
-extern char image_data[], initrd_data[];
-extern int initrd_len, image_len;
-extern unsigned int heap_max;
-extern void flush_cache(void *start, unsigned int len);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-               unsigned int progend);
-extern void setup_bats(unsigned long start);
-
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-
-#define SCRATCH_SIZE   (128 << 10)
-
-static char heap[SCRATCH_SIZE];
-
-static unsigned long ram_start = 0;
-static unsigned long ram_end = 0x1000000;
-
-static unsigned long prog_start = 0x800000;
-static unsigned long prog_size = 0x700000;
-
-typedef void (*kernel_start_t)(int, int, void *);
-
-void boot(int a1, int a2, void *prom)
-{
-    unsigned sa, len;
-    void *dst;
-    unsigned char *im;
-    unsigned initrd_start, initrd_size;
-
-    printf("coffboot starting: loaded at 0x%p\n", &_start);
-    setup_bats(ram_start);
-
-    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
-    if (initrd_size) {
-       initrd_start = (ram_end - initrd_size) & ~0xFFF;
-       a1 = initrd_start;
-       a2 = initrd_size;
-       claim(initrd_start, ram_end - initrd_start, 0);
-       printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
-              initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-       memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-       prog_size = initrd_start - prog_start;
-    } else
-       a2 = 0xdeadbeef;
-
-    im = (char *)(&__image_begin);
-    len = (char *)(&__image_end) - (char *)(&__image_begin);
-    /* claim 4MB starting at PROG_START */
-    claim(prog_start, prog_size, 0);
-    map(prog_start, prog_start, prog_size);
-    dst = (void *) prog_start;
-    if (im[0] == 0x1f && im[1] == 0x8b) {
-       /* set up scratch space */
-       begin_avail = avail_high = avail_ram = heap;
-       end_avail = heap + sizeof(heap);
-       printf("heap at 0x%p\n", avail_ram);
-       printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
-       gunzip(dst, prog_size, im, &len);
-       printf("done %u bytes\n", len);
-       printf("%u bytes of heap consumed, max in use %u\n",
-              avail_high - begin_avail, heap_max);
-    } else {
-       memmove(dst, im, len);
-    }
-
-    flush_cache(dst, len);
-    make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac,
-                   (prog_start + prog_size));
-
-    sa = (unsigned long)prog_start;
-    printf("start address = 0x%x\n", sa);
-
-    (*(kernel_start_t)sa)(a1, a2, prom);
-
-    printf("returned?\n");
-
-    pause();
-}
diff --git a/arch/ppc/boot/openfirmware/newworldmain.c b/arch/ppc/boot/openfirmware/newworldmain.c
deleted file mode 100644 (file)
index fa8a8f9..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 <linux/string.h>
-#include "nonstdio.h"
-#include "of1275.h"
-#include <asm/processor.h>
-#include <asm/page.h>
-
-/* Passed from the linker */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin[], __ramdisk_end;
-extern char _start, _end;
-
-extern unsigned int heap_max;
-extern void flush_cache(void *start, unsigned int len);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-               unsigned int progend);
-
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-
-
-#define RAM_END                (16 << 20)
-
-#define PROG_START     0x00010000
-#define PROG_SIZE      0x007f0000
-
-#define SCRATCH_SIZE   (128 << 10)
-
-typedef void (*kernel_start_t)(int, int, void *);
-
-void boot(int a1, int a2, void *prom)
-{
-    unsigned sa, len;
-    void *dst;
-    unsigned char *im;
-    unsigned initrd_start, initrd_size;
-
-    printf("chrpboot starting: loaded at 0x%p\n", &_start);
-
-    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
-    if (initrd_size) {
-       initrd_start = (RAM_END - initrd_size) & ~0xFFF;
-       a1 = initrd_start;
-       a2 = initrd_size;
-       claim(initrd_start, RAM_END - initrd_start, 0);
-       printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
-              initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-       memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-    } else
-       a2 = 0xdeadbeef;
-
-    im = (char *)(&__image_begin);
-    len = (char *)(&__image_end) - (char *)(&__image_begin);
-    /* claim 3MB starting at PROG_START */
-    claim(PROG_START, PROG_SIZE, 0);
-    dst = (void *) PROG_START;
-    if (im[0] == 0x1f && im[1] == 0x8b) {
-       /* claim some memory for scratch space */
-       avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
-       begin_avail = avail_high = avail_ram;
-       end_avail = avail_ram + SCRATCH_SIZE;
-       printf("heap at 0x%p\n", avail_ram);
-       printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
-       gunzip(dst, PROG_SIZE, im, &len);
-       printf("done %u bytes\n", len);
-       printf("%u bytes of heap consumed, max in use %u\n",
-              avail_high - begin_avail, heap_max);
-       release(begin_avail, SCRATCH_SIZE);
-    } else {
-       memmove(dst, im, len);
-    }
-
-    flush_cache(dst, len);
-    make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_Pmac,
-                   (PROG_START + PROG_SIZE));
-
-    sa = (unsigned long)PROG_START;
-    printf("start address = 0x%x\n", sa);
-
-    (*(kernel_start_t)sa)(a1, a2, prom);
-
-    printf("returned?\n");
-
-    pause();
-}
index ca020130086820b6e21956f4fc10b0d5ebf58d33..e399bbb969a4735ad4b30918eba1881210d8ac7b 100644 (file)
@@ -9,7 +9,6 @@ extra-$(CONFIG_44x)             := head_44x.o
 extra-$(CONFIG_FSL_BOOKE)      := head_fsl_booke.o
 extra-$(CONFIG_8xx)            := head_8xx.o
 extra-$(CONFIG_6xx)            += idle_6xx.o
-extra-$(CONFIG_POWER4)         += idle_power4.o
 extra-y                                += vmlinux.lds
 
 obj-y                          := entry.o traps.o idle.o time.o misc.o \
@@ -17,7 +16,6 @@ obj-y                         := entry.o traps.o idle.o time.o misc.o \
                                        ppc_htab.o
 obj-$(CONFIG_6xx)              += l2cr.o cpu_setup_6xx.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
-obj-$(CONFIG_POWER4)           += cpu_setup_power4.o
 obj-$(CONFIG_MODULES)          += module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)       += dma-mapping.o
 obj-$(CONFIG_PCI)              += pci.o
@@ -42,7 +40,6 @@ obj-$(CONFIG_6xx)             += l2cr.o cpu_setup_6xx.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o
 obj-$(CONFIG_MODULES)          += module.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)       += dma-mapping.o
-obj-$(CONFIG_PCI)              += pci.o
 obj-$(CONFIG_KGDB)             += ppc-stub.o
 obj-$(CONFIG_TAU)              += temp.o
 ifndef CONFIG_E200
index de0978742221ae6eb0ddfb7e6a60120c7c48c4fa..3e6ca7f5843ff43575b2f5e5fe834b60bf3f03dd 100644 (file)
@@ -375,6 +375,8 @@ DataStoreTLBMiss:
        lis     r11, swapper_pg_dir@h
        ori     r11, r11, swapper_pg_dir@l
        rlwimi  r10, r11, 0, 2, 19
+       stw     r12, 16(r0)
+       b LoadLargeDTLB
 3:
        lwz     r11, 0(r10)     /* Get the level 1 entry */
        rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
@@ -430,6 +432,81 @@ DataStoreTLBMiss:
 InstructionTLBError:
        b       InstructionAccess
 
+LoadLargeDTLB:
+       li      r12, 0
+       lwz     r11, 0(r10)     /* Get the level 1 entry */
+       rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */
+       beq     3f              /* If zero, don't try to find a pte */
+
+       /* We have a pte table, so load fetch the pte from the table.
+        */
+       ori     r11, r11, 1     /* Set valid bit in physical L2 page */
+       DO_8xx_CPU6(0x3b80, r3)
+       mtspr   SPRN_MD_TWC, r11        /* Load pte table base address */
+       mfspr   r10, SPRN_MD_TWC        /* ....and get the pte address */
+       lwz     r10, 0(r10)     /* Get the pte */
+
+       /* Insert the Guarded flag into the TWC from the Linux PTE.
+        * It is bit 27 of both the Linux PTE and the TWC (at least
+        * I got that right :-).  It will be better when we can put
+        * this into the Linux pgd/pmd and load it in the operation
+        * above.
+        */
+       rlwimi  r11, r10, 0, 27, 27
+
+       rlwimi  r12, r10, 0, 0, 9       /* extract phys. addr */
+       mfspr   r3, SPRN_MD_EPN
+       rlwinm  r3, r3, 0, 0, 9         /* extract virtual address */
+       tophys(r3, r3)
+       cmpw    r3, r12                 /* only use 8M page if it is a direct 
+                                          kernel mapping */
+       bne     1f
+       ori     r11, r11, MD_PS8MEG
+       li      r12, 1
+       b       2f
+1:
+       li      r12, 0          /* can't use 8MB TLB, so zero r12. */
+2:
+       DO_8xx_CPU6(0x3b80, r3)
+       mtspr   SPRN_MD_TWC, r11
+
+       /* The Linux PTE won't go exactly into the MMU TLB.
+        * Software indicator bits 21, 22 and 28 must be clear.
+        * Software indicator bits 24, 25, 26, and 27 must be
+        * set.  All other Linux PTE bits control the behavior
+        * of the MMU.
+        */
+3:     li      r11, 0x00f0
+       rlwimi  r10, r11, 0, 24, 28     /* Set 24-27, clear 28 */
+       cmpwi   r12, 1
+       bne 4f
+       ori     r10, r10, 0x8
+
+       mfspr   r12, SPRN_MD_EPN
+       lis     r3, 0xff80              /* 10-19 must be clear for 8MB TLB */
+       ori     r3, r3, 0x0fff
+       and     r12, r3, r12
+       DO_8xx_CPU6(0x3780, r3)
+       mtspr   SPRN_MD_EPN, r12
+
+       lis     r3, 0xff80              /* 10-19 must be clear for 8MB TLB */
+       ori     r3, r3, 0x0fff
+       and     r10, r3, r10
+4:
+       DO_8xx_CPU6(0x3d80, r3)
+       mtspr   SPRN_MD_RPN, r10        /* Update TLB entry */
+
+       mfspr   r10, SPRN_M_TW  /* Restore registers */
+       lwz     r11, 0(r0)
+       mtcr    r11
+       lwz     r11, 4(r0)
+
+       lwz     r12, 16(r0)
+#ifdef CONFIG_8xx_CPU6
+       lwz     r3, 8(r0)
+#endif
+       rfi
+
 /* This is the data TLB error on the MPC8xx.  This could be due to
  * many reasons, including a dirty update to a pte.  We can catch that
  * one here, but anything else is an error.  First, we track down the
index fb5658bba28592e9b55ac75ba1ae373a9fb21ca9..c3427eed8345c9164fadb4895bc9ed6aad0a3268 100644 (file)
@@ -204,78 +204,6 @@ _GLOBAL(call_setup_cpu)
        mtctr   r5
        bctr
 
-#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx)
-
-/* This gets called by via-pmu.c to switch the PLL selection
- * on 750fx CPU. This function should really be moved to some
- * other place (as most of the cpufreq code in via-pmu
- */
-_GLOBAL(low_choose_750fx_pll)
-       /* Clear MSR:EE */
-       mfmsr   r7
-       rlwinm  r0,r7,0,17,15
-       mtmsr   r0
-
-       /* If switching to PLL1, disable HID0:BTIC */
-       cmplwi  cr0,r3,0
-       beq     1f
-       mfspr   r5,SPRN_HID0
-       rlwinm  r5,r5,0,27,25
-       sync
-       mtspr   SPRN_HID0,r5
-       isync
-       sync
-
-1:
-       /* Calc new HID1 value */
-       mfspr   r4,SPRN_HID1    /* Build a HID1:PS bit from parameter */
-       rlwinm  r5,r3,16,15,15  /* Clear out HID1:PS from value read */
-       rlwinm  r4,r4,0,16,14   /* Could have I used rlwimi here ? */
-       or      r4,r4,r5
-       mtspr   SPRN_HID1,r4
-
-       /* Store new HID1 image */
-       rlwinm  r6,r1,0,0,18
-       lwz     r6,TI_CPU(r6)
-       slwi    r6,r6,2
-       addis   r6,r6,nap_save_hid1@ha
-       stw     r4,nap_save_hid1@l(r6)
-
-       /* If switching to PLL0, enable HID0:BTIC */
-       cmplwi  cr0,r3,0
-       bne     1f
-       mfspr   r5,SPRN_HID0
-       ori     r5,r5,HID0_BTIC
-       sync
-       mtspr   SPRN_HID0,r5
-       isync
-       sync
-
-1:
-       /* Return */
-       mtmsr   r7
-       blr
-
-_GLOBAL(low_choose_7447a_dfs)
-       /* Clear MSR:EE */
-       mfmsr   r7
-       rlwinm  r0,r7,0,17,15
-       mtmsr   r0
-       
-       /* Calc new HID1 value */
-       mfspr   r4,SPRN_HID1
-       insrwi  r4,r3,1,9       /* insert parameter into bit 9 */
-       sync
-       mtspr   SPRN_HID1,r4
-       sync
-       isync
-
-       /* Return */
-       mtmsr   r7
-       blr
-
-#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */
-
 /*
  * complement mask on the msr then "or" some values on.
  *     _nmask_and_or_msr(nmask, value_to_or)
index 704c846b2b0f5272a135dba226622df9c5253e3b..04d04c5bfdd0ed79b16b45cf4ee3edec8edf5cd8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Common pmac/prep/chrp pci routines. -- Cort
+ * Common prep/chrp pci routines. -- Cort
  */
 
 #include <linux/config.h>
@@ -50,8 +50,7 @@ static void fixup_cpc710_pci64(struct pci_dev* dev);
 static u8* pci_to_OF_bus_map;
 #endif
 
-/* By default, we don't re-assign bus numbers. We do this only on
- * some pmacs
+/* By default, we don't re-assign bus numbers.
  */
 int pci_assign_all_buses;
 
@@ -780,17 +779,6 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
                return NULL;
 
        /* Fixup bus number according to what OF think it is. */
-#ifdef CONFIG_PPC_PMAC
-       /* The G5 need a special case here. Basically, we don't remap all
-        * busses on it so we don't create the pci-OF-map. However, we do
-        * remap the AGP bus and so have to deal with it. A future better
-        * fix has to be done by making the remapping per-host and always
-        * filling the pci_to_OF map. --BenH
-        */
-       if (_machine == _MACH_Pmac && busnr >= 0xf0)
-               busnr -= 0xf0;
-       else
-#endif
        if (pci_to_OF_bus_map)
                busnr = pci_to_OF_bus_map[busnr];
        if (busnr == 0xff)
@@ -1040,216 +1028,6 @@ void pcibios_add_platform_entries(struct pci_dev *pdev)
 }
 
 
-#ifdef CONFIG_PPC_PMAC
-/*
- * This set of routines checks for PCI<->PCI bridges that have closed
- * IO resources and have child devices. It tries to re-open an IO
- * window on them.
- *
- * This is a _temporary_ fix to workaround a problem with Apple's OF
- * closing IO windows on P2P bridges when the OF drivers of cards
- * below this bridge don't claim any IO range (typically ATI or
- * Adaptec).
- *
- * A more complete fix would be to use drivers/pci/setup-bus.c, which
- * involves a working pcibios_fixup_pbus_ranges(), some more care about
- * ordering when creating the host bus resources, and maybe a few more
- * minor tweaks
- */
-
-/* Initialize bridges with base/limit values we have collected */
-static void __init
-do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga)
-{
-       struct pci_dev *bridge = bus->self;
-       struct pci_controller* hose = (struct pci_controller *)bridge->sysdata;
-       u32 l;
-       u16 w;
-       struct resource res;
-
-       if (bus->resource[0] == NULL)
-               return;
-       res = *(bus->resource[0]);
-
-       DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge));
-       res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
-       res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
-       DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
-
-       /* Set up the top and bottom of the PCI I/O segment for this bus. */
-       pci_read_config_dword(bridge, PCI_IO_BASE, &l);
-       l &= 0xffff000f;
-       l |= (res.start >> 8) & 0x00f0;
-       l |= res.end & 0xf000;
-       pci_write_config_dword(bridge, PCI_IO_BASE, l);
-
-       if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
-               l = (res.start >> 16) | (res.end & 0xffff0000);
-               pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l);
-       }
-
-       pci_read_config_word(bridge, PCI_COMMAND, &w);
-       w |= PCI_COMMAND_IO;
-       pci_write_config_word(bridge, PCI_COMMAND, w);
-
-#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */
-       if (enable_vga) {
-               pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w);
-               w |= PCI_BRIDGE_CTL_VGA;
-               pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w);
-       }
-#endif
-}
-
-/* This function is pretty basic and actually quite broken for the
- * general case, it's enough for us right now though. It's supposed
- * to tell us if we need to open an IO range at all or not and what
- * size.
- */
-static int __init
-check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga)
-{
-       struct pci_dev *dev;
-       int     i;
-       int     rc = 0;
-
-#define push_end(res, size) do { unsigned long __sz = (size) ; \
-       res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \
-    } while (0)
-
-       list_for_each_entry(dev, &bus->devices, bus_list) {
-               u16 class = dev->class >> 8;
-
-               if (class == PCI_CLASS_DISPLAY_VGA ||
-                   class == PCI_CLASS_NOT_DEFINED_VGA)
-                       *found_vga = 1;
-               if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate)
-                       rc |= check_for_io_childs(dev->subordinate, res, found_vga);
-               if (class == PCI_CLASS_BRIDGE_CARDBUS)
-                       push_end(res, 0xfff);
-
-               for (i=0; i<PCI_NUM_RESOURCES; i++) {
-                       struct resource *r;
-                       unsigned long r_size;
-
-                       if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI
-                           && i >= PCI_BRIDGE_RESOURCES)
-                               continue;
-                       r = &dev->resource[i];
-                       r_size = r->end - r->start;
-                       if (r_size < 0xfff)
-                               r_size = 0xfff;
-                       if (r->flags & IORESOURCE_IO && (r_size) != 0) {
-                               rc = 1;
-                               push_end(res, r_size);
-                       }
-               }
-       }
-
-       return rc;
-}
-
-/* Here we scan all P2P bridges of a given level that have a closed
- * IO window. Note that the test for the presence of a VGA card should
- * be improved to take into account already configured P2P bridges,
- * currently, we don't see them and might end up configuring 2 bridges
- * with VGA pass through enabled
- */
-static void __init
-do_fixup_p2p_level(struct pci_bus *bus)
-{
-       struct pci_bus *b;
-       int i, parent_io;
-       int has_vga = 0;
-
-       for (parent_io=0; parent_io<4; parent_io++)
-               if (bus->resource[parent_io]
-                   && bus->resource[parent_io]->flags & IORESOURCE_IO)
-                       break;
-       if (parent_io >= 4)
-               return;
-
-       list_for_each_entry(b, &bus->children, node) {
-               struct pci_dev *d = b->self;
-               struct pci_controller* hose = (struct pci_controller *)d->sysdata;
-               struct resource *res = b->resource[0];
-               struct resource tmp_res;
-               unsigned long max;
-               int found_vga = 0;
-
-               memset(&tmp_res, 0, sizeof(tmp_res));
-               tmp_res.start = bus->resource[parent_io]->start;
-
-               /* We don't let low addresses go through that closed P2P bridge, well,
-                * that may not be necessary but I feel safer that way
-                */
-               if (tmp_res.start == 0)
-                       tmp_res.start = 0x1000;
-       
-               if (!list_empty(&b->devices) && res && res->flags == 0 &&
-                   res != bus->resource[parent_io] &&
-                   (d->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-                   check_for_io_childs(b, &tmp_res, &found_vga)) {
-                       u8 io_base_lo;
-
-                       printk(KERN_INFO "Fixing up IO bus %s\n", b->name);
-
-                       if (found_vga) {
-                               if (has_vga) {
-                                       printk(KERN_WARNING "Skipping VGA, already active"
-                                           " on bus segment\n");
-                                       found_vga = 0;
-                               } else
-                                       has_vga = 1;
-                       }
-                       pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo);
-
-                       if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32)
-                               max = ((unsigned long) hose->io_base_virt
-                                       - isa_io_base) + 0xffffffff;
-                       else
-                               max = ((unsigned long) hose->io_base_virt
-                                       - isa_io_base) + 0xffff;
-
-                       *res = tmp_res;
-                       res->flags = IORESOURCE_IO;
-                       res->name = b->name;
-               
-                       /* Find a resource in the parent where we can allocate */
-                       for (i = 0 ; i < 4; i++) {
-                               struct resource *r = bus->resource[i];
-                               if (!r)
-                                       continue;
-                               if ((r->flags & IORESOURCE_IO) == 0)
-                                       continue;
-                               DBG("Trying to allocate from %08lx, size %08lx from parent"
-                                   " res %d: %08lx -> %08lx\n",
-                                       res->start, res->end, i, r->start, r->end);
-                       
-                               if (allocate_resource(r, res, res->end + 1, res->start, max,
-                                   res->end + 1, NULL, NULL) < 0) {
-                                       DBG("Failed !\n");
-                                       continue;
-                               }
-                               do_update_p2p_io_resource(b, found_vga);
-                               break;
-                       }
-               }
-               do_fixup_p2p_level(b);
-       }
-}
-
-static void
-pcibios_fixup_p2p_bridges(void)
-{
-       struct pci_bus *b;
-
-       list_for_each_entry(b, &pci_root_buses, node)
-               do_fixup_p2p_level(b);
-}
-
-#endif /* CONFIG_PPC_PMAC */
-
 static int __init
 pcibios_init(void)
 {
@@ -1290,9 +1068,6 @@ pcibios_init(void)
        pcibios_allocate_bus_resources(&pci_root_buses);
        pcibios_allocate_resources(0);
        pcibios_allocate_resources(1);
-#ifdef CONFIG_PPC_PMAC
-       pcibios_fixup_p2p_bridges();
-#endif /* CONFIG_PPC_PMAC */
        pcibios_assign_resources();
 
        /* Call machine dependent post-init code */
@@ -1722,17 +1497,6 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
        struct pci_controller* hose;
        long result = -EOPNOTSUPP;
 
-       /* Argh ! Please forgive me for that hack, but that's the
-        * simplest way to get existing XFree to not lockup on some
-        * G5 machines... So when something asks for bus 0 io base
-        * (bus 0 is HT root), we return the AGP one instead.
-        */
-#ifdef CONFIG_PPC_PMAC
-       if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4"))
-               if (bus == 0)
-                       bus = 0xf0;
-#endif /* CONFIG_PPC_PMAC */
-
        hose = pci_bus_to_hose(bus);
        if (!hose)
                return -ENODEV;
index 95075f99a6d4ea09abfb4c388a019a040d389e1c..3a6e4bcb3c53b568d54f7e773c2b9548d2ac6d7b 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
-#include <asm/pmac_feature.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
 #include <asm/hw_irq.h>
@@ -58,7 +57,6 @@ extern void machine_check_exception(struct pt_regs *regs);
 extern void alignment_exception(struct pt_regs *regs);
 extern void program_check_exception(struct pt_regs *regs);
 extern void single_step_exception(struct pt_regs *regs);
-extern int pmac_newworld;
 extern int sys_sigreturn(struct pt_regs *regs);
 
 long long __ashrdi3(long long, int);
@@ -213,10 +211,6 @@ EXPORT_SYMBOL(adb_try_handler_change);
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 #endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_PPC_PMAC
-EXPORT_SYMBOL(sys_ctrler);
-EXPORT_SYMBOL(pmac_newworld);
-#endif
 #ifdef CONFIG_PPC_OF
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
@@ -241,9 +235,6 @@ EXPORT_SYMBOL(of_node_put);
 #if defined(CONFIG_BOOTX_TEXT)
 EXPORT_SYMBOL(btext_update_display);
 #endif
-#if defined(CONFIG_SCSI) && defined(CONFIG_PPC_PMAC)
-EXPORT_SYMBOL(note_scsi_host);
-#endif
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
 #endif
@@ -270,7 +261,6 @@ EXPORT_SYMBOL(__delay);
 EXPORT_SYMBOL(timer_interrupt);
 EXPORT_SYMBOL(irq_desc);
 EXPORT_SYMBOL(tb_ticks_per_jiffy);
-EXPORT_SYMBOL(get_wchan);
 EXPORT_SYMBOL(console_drivers);
 #ifdef CONFIG_XMON
 EXPORT_SYMBOL(xmon);
index e707c6f6e61bdd729d2309befc78fc082083f300..c08ab432e95891b32e51d1e5bf31fc6f26eb22df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Common prep/pmac/chrp boot and setup code.
+ * Common prep/chrp boot and setup code.
  */
 
 #include <linux/config.h>
@@ -35,7 +35,6 @@
 #include <asm/machdep.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/pmac_feature.h>
 #include <asm/sections.h>
 #include <asm/nvram.h>
 #include <asm/xmon.h>
@@ -55,7 +54,6 @@
 
 extern void platform_init(unsigned long r3, unsigned long r4,
                unsigned long r5, unsigned long r6, unsigned long r7);
-extern void bootx_init(unsigned long r4, unsigned long phys);
 extern void identify_cpu(unsigned long offset, unsigned long cpu);
 extern void do_cpu_ftr_fixups(unsigned long offset);
 extern void reloc_got2(unsigned long offset);
@@ -80,8 +78,6 @@ EXPORT_SYMBOL(_machine);
 
 extern void prep_init(unsigned long r3, unsigned long r4,
                unsigned long r5, unsigned long r6, unsigned long r7);
-extern void pmac_init(unsigned long r3, unsigned long r4,
-               unsigned long r5, unsigned long r6, unsigned long r7);
 extern void chrp_init(unsigned long r3, unsigned long r4,
                unsigned long r5, unsigned long r6, unsigned long r7);
 
@@ -324,20 +320,15 @@ early_init(int r3, int r4, int r5)
        identify_cpu(offset, 0);
        do_cpu_ftr_fixups(offset);
 
-#if defined(CONFIG_PPC_MULTIPLATFORM)
+#if defined(CONFIG_PPC_OF)
        reloc_got2(offset);
 
-       /* If we came here from BootX, clear the screen,
-        * set up some pointers and return. */
-       if ((r3 == 0x426f6f58) && (r5 == 0))
-               bootx_init(r4, phys);
-
        /*
         * don't do anything on prep
         * for now, don't use bootinfo because it breaks yaboot 0.5
         * and assume that if we didn't find a magic number, we have OF
         */
-       else if (*(unsigned long *)(0) != 0xdeadc0de)
+       if (*(unsigned long *)(0) != 0xdeadc0de)
                phys = prom_init(r3, r4, (prom_entry)r5);
 
        reloc_got2(-offset);
@@ -424,6 +415,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
        }
 #endif
 
+#ifdef CONFIG_PPC_OF
        have_of = 1;
 
        /* prom_init has already been called from __start */
@@ -495,19 +487,17 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 #endif /* CONFIG_ADB */
 
        switch (_machine) {
-#ifdef CONFIG_PPC_PMAC
-       case _MACH_Pmac:
-               pmac_init(r3, r4, r5, r6, r7);
-               break;
-#endif
 #ifdef CONFIG_PPC_CHRP
        case _MACH_chrp:
                chrp_init(r3, r4, r5, r6, r7);
                break;
 #endif
        }
+#endif /* CONFIG_PPC_OF */
 }
+#endif /* CONFIG_PPC_MULTIPLATFORM */
 
+#ifdef CONFIG_PPC_OF
 #ifdef CONFIG_SERIAL_CORE_CONSOLE
 extern char *of_stdout_device;
 
@@ -564,7 +554,7 @@ static int __init set_preferred_console(void)
 }
 console_initcall(set_preferred_console);
 #endif /* CONFIG_SERIAL_CORE_CONSOLE */
-#endif /* CONFIG_PPC_MULTIPLATFORM */
+#endif /* CONFIG_PPC_OF */
 
 struct bi_record *find_bootinfo(void)
 {
@@ -747,14 +737,6 @@ void __init setup_arch(char **cmdline_p)
        if (ppc_md.init_early)
                ppc_md.init_early();
 
-#ifdef CONFIG_PPC_MULTIPLATFORM
-       /* This could be called "early setup arch", it must be done
-        * now because xmon need it
-        */
-       if (_machine == _MACH_Pmac)
-               pmac_feature_init();    /* New cool way */
-#endif
-
 #ifdef CONFIG_XMON
        xmon_init(1);
        if (strstr(cmd_line, "xmon"))
index 9dbc4d28fa281cf6d8c83810e3204acb92eecf48..6d0a1838d94cc4badc79fd46552ef6f83be106cc 100644 (file)
@@ -38,9 +38,6 @@
 #include <asm/io.h>
 #include <asm/reg.h>
 #include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
 #include <asm/pmc.h>
 
 #ifdef CONFIG_XMON
@@ -85,12 +82,6 @@ int die(const char * str, struct pt_regs * fp, long err)
        int nl = 0;
        console_verbose();
        spin_lock_irq(&die_lock);
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if (_machine == _MACH_Pmac) {
-               set_backlight_enable(1);
-               set_backlight_level(BACKLIGHT_MAX);
-       }
-#endif
        printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
 #ifdef CONFIG_PREEMPT
        printk("PREEMPT ");
@@ -159,7 +150,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
  */
 static inline int check_io_access(struct pt_regs *regs)
 {
-#if defined CONFIG_PPC_PMAC || defined CONFIG_8xx
+#if defined CONFIG_8xx
        unsigned long msr = regs->msr;
        const struct exception_table_entry *entry;
        unsigned int *nip = (unsigned int *)regs->nip;
@@ -196,7 +187,7 @@ static inline int check_io_access(struct pt_regs *regs)
                        return 1;
                }
        }
-#endif /* CONFIG_PPC_PMAC */
+#endif /* CONFIG_8xx */
        return 0;
 }
 
index 45f0782059f1a4be97451a6abfc2ccfa82443ba2..134db5c0420319bbe31888b6b06cb3844849e214 100644 (file)
@@ -67,10 +67,6 @@ unsigned long ppc_memoffset = PAGE_OFFSET;
 int mem_init_done;
 int init_bootmem_done;
 int boot_mapsize;
-#ifdef CONFIG_PPC_PMAC
-unsigned long agp_special_page;
-EXPORT_SYMBOL(agp_special_page);
-#endif
 
 extern char _end[];
 extern char etext[], _stext[];
@@ -423,10 +419,6 @@ void __init mem_init(void)
                     addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ;
                     addr += PAGE_SIZE)
                        SetPageReserved(virt_to_page(addr));
-#endif
-#ifdef CONFIG_PPC_PMAC
-       if (agp_special_page)
-               SetPageReserved(virt_to_page(agp_special_page));
 #endif
        for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory;
             addr += PAGE_SIZE) {
@@ -463,11 +455,6 @@ void __init mem_init(void)
               initpages<< (PAGE_SHIFT-10),
               (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
 
-#ifdef CONFIG_PPC_PMAC
-       if (agp_special_page)
-               printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page);
-#endif
-
        mem_init_done = 1;
 }
 
@@ -512,22 +499,6 @@ set_phys_avail(unsigned long total_memory)
        if (rtas_data)
                mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1);
 #endif
-#ifdef CONFIG_PPC_PMAC
-       /* Because of some uninorth weirdness, we need a page of
-        * memory as high as possible (it must be outside of the
-        * bus address seen as the AGP aperture). It will be used
-        * by the r128 DRM driver
-        *
-        * FIXME: We need to make sure that page doesn't overlap any of the\
-        * above. This could be done by improving mem_pieces_find to be able
-        * to do a backward search from the end of the list.
-        */
-       if (_machine == _MACH_Pmac && find_devices("uni-north-agp")) {
-               agp_special_page = (total_memory - PAGE_SIZE);
-               mem_pieces_remove(&phys_avail, agp_special_page, PAGE_SIZE, 0);
-               agp_special_page = (unsigned long)__va(agp_special_page);
-       }
-#endif /* CONFIG_PPC_PMAC */
 }
 
 /* Mark some memory as reserved by removing it from phys_avail. */
index 04bdc39bf47b473f762ffbfc8d4a3d58c70671d9..012e1e652c03ed6e039e0c56254fe913f8d1ffbb 100644 (file)
@@ -51,9 +51,6 @@
 
 #include <syslib/ppc83xx_setup.h>
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-
 #ifndef CONFIG_PCI
 unsigned long isa_io_base = 0;
 unsigned long isa_mem_base = 0;
@@ -129,20 +126,21 @@ mpc834x_sys_setup_arch(void)
        mdata->irq[1] = MPC83xx_IRQ_EXT2;
        mdata->irq[2] = -1;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_0;
+               pdata->bus_id = 0;
+               pdata->phy_id = 0;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_1;
+               pdata->bus_id = 0;
+               pdata->phy_id = 1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
index c5cde97c6ef00b2832a9949c884b977d83578ba7..2eceb1e6f4eb956c5266be833f7b810ae42500cd 100644 (file)
 
 #include <syslib/ppc85xx_setup.h>
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-static const char *GFAR_PHY_3 = "phy0:3";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -102,27 +98,29 @@ mpc8540ads_setup_arch(void)
        mdata->irq[2] = -1;
        mdata->irq[3] = MPC85xx_IRQ_EXT5;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_0;
+               pdata->bus_id = 0;
+               pdata->phy_id = 0;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_1;
+               pdata->bus_id = 0;
+               pdata->phy_id = 1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
        if (pdata) {
                pdata->board_flags = 0;
-               pdata->bus_id = GFAR_PHY_3;
+               pdata->bus_id = 0;
+               pdata->phy_id = 3;
                memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
        }
 
index 8e39a551709292fd8935d88a9c8591110cb42068..442c7ff195d3c16e4bc241d48e0ebfc29d4fcd7c 100644 (file)
 #include <syslib/ppc85xx_setup.h>
 
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-static const char *GFAR_PHY_3 = "phy0:3";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -99,20 +95,21 @@ mpc8560ads_setup_arch(void)
        mdata->irq[2] = -1;
        mdata->irq[3] = MPC85xx_IRQ_EXT5;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_0;
+               pdata->bus_id = 0;
+               pdata->phy_id = 0;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_1;
+               pdata->bus_id = 0;
+               pdata->phy_id = 1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
index 2959e3c4083d0ff322c8c0f77462c7efedf6d7ea..b332ebae6bd3018296b047ebbdc0146db653f48f 100644 (file)
@@ -395,9 +395,6 @@ mpc85xx_cds_pcibios_fixup(void)
 
 TODC_ALLOC();
 
-static const char *GFAR_PHY_0 = "phy0:0";
-static const char *GFAR_PHY_1 = "phy0:1";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -461,34 +458,37 @@ mpc85xx_cds_setup_arch(void)
        mdata->irq[2] = -1;
        mdata->irq[3] = -1;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_0;
+               pdata->bus_id = 0;
+               pdata->phy_id = 0;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_1;
+               pdata->bus_id = 0;
+               pdata->phy_id = 1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_0;
+               pdata->bus_id = 0;
+               pdata->phy_id = 0;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_eTSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_1;
+               pdata->bus_id = 0;
+               pdata->phy_id = 1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
index 45a5b81b4ed1ae4da5e81fa88fe280ea930b3401..e777ba824aa90c00d25453df347f72415aa0f2e1 100644 (file)
@@ -91,9 +91,6 @@ sbc8560_early_serial_map(void)
 }
 #endif
 
-static const char *GFAR_PHY_25 = "phy0:25";
-static const char *GFAR_PHY_26 = "phy0:26";
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -136,20 +133,21 @@ sbc8560_setup_arch(void)
        mdata->irq[25] = MPC85xx_IRQ_EXT6;
        mdata->irq[26] = MPC85xx_IRQ_EXT7;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_25;
+               pdata->bus_id = 0;
+               pdata->phy_id = 25;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_26;
+               pdata->bus_id = 0;
+               pdata->phy_id = 26;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
index 15ce9d070634eb26793e2800365674d5ddc84cb7..061bb7cf2d9a18ca12b9b7c6f4058b8de42c0f7d 100644 (file)
@@ -93,9 +93,6 @@ static u8 gp3_openpic_initsenses[] __initdata = {
        0x0,                            /* External 11: */
 };
 
-static const char *GFAR_PHY_2 = "phy0:2";
-static const char *GFAR_PHY_4 = "phy0:4";
-
 /*
  * Setup the architecture
  */
@@ -130,20 +127,21 @@ gp3_setup_arch(void)
        mdata->irq[2] = MPC85xx_IRQ_EXT5;
        mdata->irq[4] = MPC85xx_IRQ_EXT5;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
        if (pdata) {
        /*      pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
-               pdata->bus_id = GFAR_PHY_2;
+               pdata->bus_id = 0;
+               pdata->phy_id = 2;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
        if (pdata) {
        /*      pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
-               pdata->bus_id = GFAR_PHY_4;
+               pdata->bus_id = 0;
+               pdata->phy_id = 4;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
index c6dfd8f0f9df963f75e6b859b11266c6d775e31b..b436f4d0a3fa753e2a1b54764dbcab0b0150a26f 100644 (file)
@@ -91,12 +91,6 @@ static u_char tqm85xx_openpic_initsenses[] __initdata = {
        0x0,                            /* External 11: */
 };
 
-static const char *GFAR_PHY_0 = "phy0:2";
-static const char *GFAR_PHY_1 = "phy0:1";
-#ifdef CONFIG_MPC8540
-static const char *GFAR_PHY_3 = "phy0:3";
-#endif
-
 /* ************************************************************************
  *
  * Setup the architecture
@@ -149,20 +143,21 @@ tqm85xx_setup_arch(void)
        mdata->irq[2] = -1;
        mdata->irq[3] = MPC85xx_IRQ_EXT8;
        mdata->irq[31] = -1;
-       mdata->paddr += binfo->bi_immr_base;
 
        /* setup the board related information for the enet controllers */
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_0;
+               pdata->bus_id = 0;
+               pdata->phy_id = 2;
                memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
        }
 
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
        if (pdata) {
                pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
-               pdata->bus_id = GFAR_PHY_1;
+               pdata->bus_id = 0;
+               pdata->phy_id = 1;
                memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
        }
 
@@ -170,7 +165,8 @@ tqm85xx_setup_arch(void)
        pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
        if (pdata) {
                pdata->board_flags = 0;
-               pdata->bus_id = GFAR_PHY_3;
+               pdata->bus_id = 0;
+               pdata->phy_id = 3;
                memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
        }
 #endif
index 7c5cdabf6f3c159a3448d2563628c8581917ee9d..51430e294b322beea0d0cd221c720eadead6369e 100644 (file)
@@ -3,26 +3,18 @@
 #
 
 # Extra CFLAGS so we don't have to do relative includes
-CFLAGS_pmac_setup.o    += -Iarch/$(ARCH)/mm
+CFLAGS_chrp_setup.o    += -Iarch/$(ARCH)/mm
 
 obj-$(CONFIG_APUS)             += apus_setup.o
 ifeq ($(CONFIG_APUS),y)
 obj-$(CONFIG_PCI)              += apus_pci.o
 endif
-obj-$(CONFIG_PPC_PMAC)         += pmac_pic.o pmac_setup.o pmac_time.o \
-                                       pmac_feature.o pmac_pci.o pmac_sleep.o \
-                                       pmac_low_i2c.o pmac_cache.o
 obj-$(CONFIG_PPC_CHRP)         += chrp_setup.o chrp_time.o chrp_pci.o \
                                        chrp_pegasos_eth.o
 ifeq ($(CONFIG_PPC_CHRP),y)
 obj-$(CONFIG_NVRAM)            += chrp_nvram.o
 endif
 obj-$(CONFIG_PPC_PREP)         += prep_pci.o prep_setup.o
-ifeq ($(CONFIG_PPC_PMAC),y)
-obj-$(CONFIG_NVRAM)            += pmac_nvram.o
-obj-$(CONFIG_CPU_FREQ_PMAC)    += pmac_cpufreq.o
-endif
-obj-$(CONFIG_PMAC_BACKLIGHT)   += pmac_backlight.o
 obj-$(CONFIG_PREP_RESIDUAL)    += residual.o
 obj-$(CONFIG_PQ2ADS)           += pq2ads.o
 obj-$(CONFIG_TQM8260)          += tqm8260_setup.o
@@ -47,6 +39,5 @@ obj-$(CONFIG_LITE5200)                += lite5200.o
 obj-$(CONFIG_EV64360)          += ev64360.o
 
 ifeq ($(CONFIG_SMP),y)
-obj-$(CONFIG_PPC_PMAC)         += pmac_smp.o
 obj-$(CONFIG_PPC_CHRP)         += chrp_smp.o
 endif
index bd047aac01b1fbd5945eb6cf38201a943f605c87..c7fe6182bb7719bad6f7ed1ede1a4b613d9fd089 100644 (file)
@@ -275,7 +275,7 @@ chrp_find_bridges(void)
                        setup_python(hose, dev);
                } else if (is_mot
                           || strncmp(model, "Motorola, Grackle", 17) == 0) {
-                       setup_grackle(hose);
+                       setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
                } else if (is_longtrail) {
                        void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
                        hose->ops = &gg2_pci_ops;
index 056ac2a7b5c15bc0bebc2dcd4fbf903284910363..48996b787378f6e985c63de3525e5b69d14c3069 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/i8259.h>
 #include <asm/open_pic.h>
 #include <asm/xmon.h>
+#include "mem_pieces.h"
 
 unsigned long chrp_get_rtc_time(void);
 int chrp_set_rtc_time(unsigned long nowtime);
@@ -65,7 +66,6 @@ void rtas_display_progress(char *, unsigned short);
 void rtas_indicator_progress(char *, unsigned short);
 void btext_progress(char *, unsigned short);
 
-extern unsigned long pmac_find_end_of_memory(void);
 extern int of_show_percpuinfo(struct seq_file *, int);
 
 int _chrp_type;
@@ -467,6 +467,75 @@ chrp_init2(void)
                ppc_md.progress("  Have fun!    ", 0x7777);
 }
 
+static struct device_node *memory_node;
+
+static int __init get_mem_prop(char *name, struct mem_pieces *mp)
+{
+       struct reg_property *rp;
+       int i, s;
+       unsigned int *ip;
+       int nac = prom_n_addr_cells(memory_node);
+       int nsc = prom_n_size_cells(memory_node);
+
+       ip = (unsigned int *) get_property(memory_node, name, &s);
+       if (ip == NULL) {
+               printk(KERN_ERR "error: couldn't get %s property on /memory\n",
+                      name);
+               return 0;
+       }
+       s /= (nsc + nac) * 4;
+       rp = mp->regions;
+       for (i = 0; i < s; ++i, ip += nac+nsc) {
+               if (nac >= 2 && ip[nac-2] != 0)
+                       continue;
+               rp->address = ip[nac-1];
+               if (nsc >= 2 && ip[nac+nsc-2] != 0)
+                       rp->size = ~0U;
+               else
+                       rp->size = ip[nac+nsc-1];
+               ++rp;
+       }
+       mp->n_regions = rp - mp->regions;
+
+       /* Make sure the pieces are sorted. */
+       mem_pieces_sort(mp);
+       mem_pieces_coalesce(mp);
+       return 1;
+}
+
+static unsigned long __init chrp_find_end_of_memory(void)
+{
+       unsigned long a, total;
+       struct mem_pieces phys_mem;
+
+       /*
+        * Find out where physical memory is, and check that it
+        * starts at 0 and is contiguous.  It seems that RAM is
+        * always physically contiguous on Power Macintoshes.
+        *
+        * Supporting discontiguous physical memory isn't hard,
+        * it just makes the virtual <-> physical mapping functions
+        * more complicated (or else you end up wasting space
+        * in mem_map).
+        */
+       memory_node = find_devices("memory");
+       if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
+           || phys_mem.n_regions == 0)
+               panic("No RAM??");
+       a = phys_mem.regions[0].address;
+       if (a != 0)
+               panic("RAM doesn't start at physical address 0");
+       total = phys_mem.regions[0].size;
+
+       if (phys_mem.n_regions > 1) {
+               printk("RAM starting at 0x%x is not contiguous\n",
+                      phys_mem.regions[1].address);
+               printk("Using RAM from 0 to 0x%lx\n", total-1);
+       }
+
+       return total;
+}
+
 void __init
 chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
          unsigned long r6, unsigned long r7)
@@ -525,7 +594,7 @@ chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
        ppc_md.get_rtc_time   = chrp_get_rtc_time;
        ppc_md.calibrate_decr = chrp_calibrate_decr;
 
-       ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+       ppc_md.find_end_of_memory = chrp_find_end_of_memory;
 
        if (rtas_data) {
                struct device_node *rtas;
index 29d074c305f05b532b4256b8ab8cb34b3df6480e..57753a55b5806ecb1005aeea7875f59087025def 100644 (file)
@@ -163,13 +163,75 @@ unsigned long chrp_get_rtc_time(void)
        return mktime(year, mon, day, hour, min, sec);
 }
 
+/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6       4700000 /* time 1 frequency * 6 */
+
+/* VIA registers */
+#define RS             0x200           /* skip between registers */
+#define T1CL           (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH           (5*RS)          /* Timer 1 counter (high 8 bits) */
+#define T1LL           (6*RS)          /* Timer 1 latch (low 8 bits) */
+#define T1LH           (7*RS)          /* Timer 1 latch (high 8 bits) */
+#define ACR            (11*RS)         /* Auxiliary control register */
+#define IFR            (13*RS)         /* Interrupt flag register */
+
+/* Bits in ACR */
+#define T1MODE         0xc0            /* Timer 1 mode */
+#define T1MODE_CONT    0x40            /*  continuous interrupts */
+
+/* Bits in IFR and IER */
+#define T1_INT         0x40            /* Timer 1 interrupt */
+
+static int __init chrp_via_calibrate_decr(void)
+{
+       struct device_node *vias;
+       volatile unsigned char __iomem *via;
+       int count = VIA_TIMER_FREQ_6 / 100;
+       unsigned int dstart, dend;
+
+       vias = find_devices("via-cuda");
+       if (vias == 0)
+               vias = find_devices("via");
+       if (vias == 0 || vias->n_addrs == 0)
+               return 0;
+       via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
+
+       /* set timer 1 for continuous interrupts */
+       out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
+       /* set the counter to a small value */
+       out_8(&via[T1CH], 2);
+       /* set the latch to `count' */
+       out_8(&via[T1LL], count);
+       out_8(&via[T1LH], count >> 8);
+       /* wait until it hits 0 */
+       while ((in_8(&via[IFR]) & T1_INT) == 0)
+               ;
+       dstart = get_dec();
+       /* clear the interrupt & wait until it hits 0 again */
+       in_8(&via[T1CL]);
+       while ((in_8(&via[IFR]) & T1_INT) == 0)
+               ;
+       dend = get_dec();
+
+       tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100);
+       tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
+
+       printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
+              tb_ticks_per_jiffy, dstart - dend);
+
+       iounmap(via);
+       
+       return 1;
+}
 
 void __init chrp_calibrate_decr(void)
 {
        struct device_node *cpu;
        unsigned int freq, *fp;
 
-       if (via_calibrate_decr())
+       if (chrp_via_calibrate_decr())
                return;
 
        /*
diff --git a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c
deleted file mode 100644 (file)
index 8be2f7d..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Miscellaneous procedures for dealing with the PowerMac hardware.
- * Contains support for the backlight.
- *
- *   Copyright (C) 2000 Benjamin Herrenschmidt
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/reboot.h>
-#include <linux/nvram.h>
-#include <linux/console.h>
-#include <asm/sections.h>
-#include <asm/ptrace.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-#include <asm/backlight.h>
-
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-static struct backlight_controller *backlighter;
-static void* backlighter_data;
-static int backlight_autosave;
-static int backlight_level = BACKLIGHT_MAX;
-static int backlight_enabled = 1;
-static int backlight_req_level = -1;
-static int backlight_req_enable = -1;
-
-static void backlight_callback(void *);
-static DECLARE_WORK(backlight_work, backlight_callback, NULL);
-
-void register_backlight_controller(struct backlight_controller *ctrler,
-                                         void *data, char *type)
-{
-       struct device_node* bk_node;
-       char *prop;
-       int valid = 0;
-
-       /* There's already a matching controller, bail out */
-       if (backlighter != NULL)
-               return;
-
-       bk_node = find_devices("backlight");
-
-#ifdef CONFIG_ADB_PMU
-       /* Special case for the old PowerBook since I can't test on it */
-       backlight_autosave = machine_is_compatible("AAPL,3400/2400")
-               || machine_is_compatible("AAPL,3500");
-       if ((backlight_autosave
-            || machine_is_compatible("AAPL,PowerBook1998")
-            || machine_is_compatible("PowerBook1,1"))
-           && !strcmp(type, "pmu"))
-               valid = 1;
-#endif
-       if (bk_node) {
-               prop = get_property(bk_node, "backlight-control", NULL);
-               if (prop && !strncmp(prop, type, strlen(type)))
-                       valid = 1;
-       }
-       if (!valid)
-               return;
-       backlighter = ctrler;
-       backlighter_data = data;
-
-       if (bk_node && !backlight_autosave)
-               prop = get_property(bk_node, "bklt", NULL);
-       else
-               prop = NULL;
-       if (prop) {
-               backlight_level = ((*prop)+1) >> 1;
-               if (backlight_level > BACKLIGHT_MAX)
-                       backlight_level = BACKLIGHT_MAX;
-       }
-
-#ifdef CONFIG_ADB_PMU
-       if (backlight_autosave) {
-               struct adb_request req;
-               pmu_request(&req, NULL, 2, 0xd9, 0);
-               while (!req.complete)
-                       pmu_poll();
-               backlight_level = req.reply[0] >> 4;
-       }
-#endif
-       acquire_console_sem();
-       if (!backlighter->set_enable(1, backlight_level, data))
-               backlight_enabled = 1;
-       release_console_sem();
-
-       printk(KERN_INFO "Registered \"%s\" backlight controller,"
-              "level: %d/15\n", type, backlight_level);
-}
-EXPORT_SYMBOL(register_backlight_controller);
-
-void unregister_backlight_controller(struct backlight_controller
-                                           *ctrler, void *data)
-{
-       /* We keep the current backlight level (for now) */
-       if (ctrler == backlighter && data == backlighter_data)
-               backlighter = NULL;
-}
-EXPORT_SYMBOL(unregister_backlight_controller);
-
-static int __set_backlight_enable(int enable)
-{
-       int rc;
-
-       if (!backlighter)
-               return -ENODEV;
-       acquire_console_sem();
-       rc = backlighter->set_enable(enable, backlight_level,
-                                    backlighter_data);
-       if (!rc)
-               backlight_enabled = enable;
-       release_console_sem();
-       return rc;
-}
-int set_backlight_enable(int enable)
-{
-       if (!backlighter)
-               return -ENODEV;
-       backlight_req_enable = enable;
-       schedule_work(&backlight_work);
-       return 0;
-}
-
-EXPORT_SYMBOL(set_backlight_enable);
-
-int get_backlight_enable(void)
-{
-       if (!backlighter)
-               return -ENODEV;
-       return backlight_enabled;
-}
-EXPORT_SYMBOL(get_backlight_enable);
-
-static int __set_backlight_level(int level)
-{
-       int rc = 0;
-
-       if (!backlighter)
-               return -ENODEV;
-       if (level < BACKLIGHT_MIN)
-               level = BACKLIGHT_OFF;
-       if (level > BACKLIGHT_MAX)
-               level = BACKLIGHT_MAX;
-       acquire_console_sem();
-       if (backlight_enabled)
-               rc = backlighter->set_level(level, backlighter_data);
-       if (!rc)
-               backlight_level = level;
-       release_console_sem();
-       if (!rc && !backlight_autosave) {
-               level <<=1;
-               if (level & 0x10)
-                       level |= 0x01;
-               // -- todo: save to property "bklt"
-       }
-       return rc;
-}
-int set_backlight_level(int level)
-{
-       if (!backlighter)
-               return -ENODEV;
-       backlight_req_level = level;
-       schedule_work(&backlight_work);
-       return 0;
-}
-
-EXPORT_SYMBOL(set_backlight_level);
-
-int get_backlight_level(void)
-{
-       if (!backlighter)
-               return -ENODEV;
-       return backlight_level;
-}
-EXPORT_SYMBOL(get_backlight_level);
-
-static void backlight_callback(void *dummy)
-{
-       int level, enable;
-
-       do {
-               level = backlight_req_level;
-               enable = backlight_req_enable;
-               mb();
-
-               if (level >= 0)
-                       __set_backlight_level(level);
-               if (enable >= 0)
-                       __set_backlight_enable(enable);
-       } while(cmpxchg(&backlight_req_level, level, -1) != level ||
-               cmpxchg(&backlight_req_enable, enable, -1) != enable);
-}
diff --git a/arch/ppc/platforms/pmac_cache.S b/arch/ppc/platforms/pmac_cache.S
deleted file mode 100644 (file)
index fb977de..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * This file contains low-level cache management functions
- * used for sleep and CPU speed changes on Apple machines.
- * (In fact the only thing that is Apple-specific is that we assume
- * that we can read from ROM at physical address 0xfff00000.)
- *
- *    Copyright (C) 2004 Paul Mackerras (paulus@samba.org) and
- *                       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 Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-#include <asm/cputable.h>
-
-/*
- * Flush and disable all data caches (dL1, L2, L3). This is used
- * when going to sleep, when doing a PMU based cpufreq transition,
- * or when "offlining" a CPU on SMP machines. This code is over
- * paranoid, but I've had enough issues with various CPU revs and
- * bugs that I decided it was worth beeing over cautious
- */
-
-_GLOBAL(flush_disable_caches)
-#ifndef CONFIG_6xx
-       blr
-#else
-BEGIN_FTR_SECTION
-       b       flush_disable_745x
-END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
-BEGIN_FTR_SECTION
-       b       flush_disable_75x
-END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
-       b       __flush_disable_L1
-
-/* This is the code for G3 and 74[01]0 */
-flush_disable_75x:
-       mflr    r10
-
-       /* Turn off EE and DR in MSR */
-       mfmsr   r11
-       rlwinm  r0,r11,0,~MSR_EE
-       rlwinm  r0,r0,0,~MSR_DR
-       sync
-       mtmsr   r0
-       isync
-
-       /* Stop DST streams */
-BEGIN_FTR_SECTION
-       DSSALL
-       sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-
-       /* Stop DPM */
-       mfspr   r8,SPRN_HID0            /* Save SPRN_HID0 in r8 */
-       rlwinm  r4,r8,0,12,10           /* Turn off HID0[DPM] */
-       sync
-       mtspr   SPRN_HID0,r4            /* Disable DPM */
-       sync
-
-       /* Disp-flush L1. We have a weird problem here that I never
-        * totally figured out. On 750FX, using the ROM for the flush
-        * results in a non-working flush. We use that workaround for
-        * now until I finally understand what's going on. --BenH
-        */
-
-       /* ROM base by default */
-       lis     r4,0xfff0
-       mfpvr   r3
-       srwi    r3,r3,16
-       cmplwi  cr0,r3,0x7000
-       bne+    1f
-       /* RAM base on 750FX */
-       li      r4,0
-1:     li      r4,0x4000
-       mtctr   r4
-1:     lwz     r0,0(r4)
-       addi    r4,r4,32
-       bdnz    1b
-       sync
-       isync
-
-       /* Disable / invalidate / enable L1 data */
-       mfspr   r3,SPRN_HID0
-       rlwinm  r3,r3,0,~(HID0_DCE | HID0_ICE)
-       mtspr   SPRN_HID0,r3
-       sync
-       isync
-       ori     r3,r3,(HID0_DCE|HID0_DCI|HID0_ICE|HID0_ICFI)
-       sync
-       isync
-       mtspr   SPRN_HID0,r3
-       xori    r3,r3,(HID0_DCI|HID0_ICFI)
-       mtspr   SPRN_HID0,r3
-       sync
-
-       /* Get the current enable bit of the L2CR into r4 */
-       mfspr   r5,SPRN_L2CR
-       /* Set to data-only (pre-745x bit) */
-       oris    r3,r5,L2CR_L2DO@h
-       b       2f
-       /* When disabling L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r3
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     /* disp-flush L2. The interesting thing here is that the L2 can be
-        * up to 2Mb ... so using the ROM, we'll end up wrapping back to memory
-        * but that is probbaly fine. We disp-flush over 4Mb to be safe
-        */
-       lis     r4,2
-       mtctr   r4
-       lis     r4,0xfff0
-1:     lwz     r0,0(r4)
-       addi    r4,r4,32
-       bdnz    1b
-       sync
-       isync
-       lis     r4,2
-       mtctr   r4
-       lis     r4,0xfff0
-1:     dcbf    0,r4
-       addi    r4,r4,32
-       bdnz    1b
-       sync
-       isync
-
-       /* now disable L2 */
-       rlwinm  r5,r5,0,~L2CR_L2E
-       b       2f
-       /* When disabling L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r5
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     sync
-       isync
-       /* Invalidate L2. This is pre-745x, we clear the L2I bit ourselves */
-       oris    r4,r5,L2CR_L2I@h
-       mtspr   SPRN_L2CR,r4
-       sync
-       isync
-
-       /* Wait for the invalidation to complete */
-1:     mfspr   r3,SPRN_L2CR
-       rlwinm. r0,r3,0,31,31
-       bne     1b
-
-       /* Clear L2I */
-       xoris   r4,r4,L2CR_L2I@h
-       sync
-       mtspr   SPRN_L2CR,r4
-       sync
-
-       /* now disable the L1 data cache */
-       mfspr   r0,SPRN_HID0
-       rlwinm  r0,r0,0,~(HID0_DCE|HID0_ICE)
-       mtspr   SPRN_HID0,r0
-       sync
-       isync
-
-       /* Restore HID0[DPM] to whatever it was before */
-       sync
-       mfspr   r0,SPRN_HID0
-       rlwimi  r0,r8,0,11,11           /* Turn back HID0[DPM] */
-       mtspr   SPRN_HID0,r0
-       sync
-
-       /* restore DR and EE */
-       sync
-       mtmsr   r11
-       isync
-
-       mtlr    r10
-       blr
-
-/* This code is for 745x processors */
-flush_disable_745x:
-       /* Turn off EE and DR in MSR */
-       mfmsr   r11
-       rlwinm  r0,r11,0,~MSR_EE
-       rlwinm  r0,r0,0,~MSR_DR
-       sync
-       mtmsr   r0
-       isync
-
-       /* Stop prefetch streams */
-       DSSALL
-       sync
-
-       /* Disable L2 prefetching */
-       mfspr   r0,SPRN_MSSCR0
-       rlwinm  r0,r0,0,0,29
-       mtspr   SPRN_MSSCR0,r0
-       sync
-       isync
-       lis     r4,0
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-       dcbf    0,r4
-
-       /* Due to a bug with the HW flush on some CPU revs, we occasionally
-        * experience data corruption. I'm adding a displacement flush along
-        * with a dcbf loop over a few Mb to "help". The problem isn't totally
-        * fixed by this in theory, but at least, in practice, I couldn't reproduce
-        * it even with a big hammer...
-        */
-
-        lis     r4,0x0002
-        mtctr   r4
-       li      r4,0
-1:
-        lwz     r0,0(r4)
-        addi    r4,r4,32                /* Go to start of next cache line */
-        bdnz    1b
-        isync
-
-        /* Now, flush the first 4MB of memory */
-        lis     r4,0x0002
-        mtctr   r4
-       li      r4,0
-        sync
-1:
-        dcbf    0,r4
-        addi    r4,r4,32                /* Go to start of next cache line */
-        bdnz    1b
-
-       /* Flush and disable the L1 data cache */
-       mfspr   r6,SPRN_LDSTCR
-       lis     r3,0xfff0       /* read from ROM for displacement flush */
-       li      r4,0xfe         /* start with only way 0 unlocked */
-       li      r5,128          /* 128 lines in each way */
-1:     mtctr   r5
-       rlwimi  r6,r4,0,24,31
-       mtspr   SPRN_LDSTCR,r6
-       sync
-       isync
-2:     lwz     r0,0(r3)        /* touch each cache line */
-       addi    r3,r3,32
-       bdnz    2b
-       rlwinm  r4,r4,1,24,30   /* move on to the next way */
-       ori     r4,r4,1
-       cmpwi   r4,0xff         /* all done? */
-       bne     1b
-       /* now unlock the L1 data cache */
-       li      r4,0
-       rlwimi  r6,r4,0,24,31
-       sync
-       mtspr   SPRN_LDSTCR,r6
-       sync
-       isync
-
-       /* Flush the L2 cache using the hardware assist */
-       mfspr   r3,SPRN_L2CR
-       cmpwi   r3,0            /* check if it is enabled first */
-       bge     4f
-       oris    r0,r3,(L2CR_L2IO_745x|L2CR_L2DO_745x)@h
-       b       2f
-       /* When disabling/locking L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r0    /* lock the L2 cache */
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     sync
-       isync
-       ori     r0,r3,L2CR_L2HWF_745x
-       sync
-       mtspr   SPRN_L2CR,r0    /* set the hardware flush bit */
-3:     mfspr   r0,SPRN_L2CR    /* wait for it to go to 0 */
-       andi.   r0,r0,L2CR_L2HWF_745x
-       bne     3b
-       sync
-       rlwinm  r3,r3,0,~L2CR_L2E
-       b       2f
-       /* When disabling L2, code must be in L1 */
-       .balign 32
-1:     mtspr   SPRN_L2CR,r3    /* disable the L2 cache */
-3:     sync
-       isync
-       b       1f
-2:     b       3f
-3:     sync
-       isync
-       b       1b
-1:     sync
-       isync
-       oris    r4,r3,L2CR_L2I@h
-       mtspr   SPRN_L2CR,r4
-       sync
-       isync
-1:     mfspr   r4,SPRN_L2CR
-       andis.  r0,r4,L2CR_L2I@h
-       bne     1b
-       sync
-
-BEGIN_FTR_SECTION
-       /* Flush the L3 cache using the hardware assist */
-4:     mfspr   r3,SPRN_L3CR
-       cmpwi   r3,0            /* check if it is enabled */
-       bge     6f
-       oris    r0,r3,L3CR_L3IO@h
-       ori     r0,r0,L3CR_L3DO
-       sync
-       mtspr   SPRN_L3CR,r0    /* lock the L3 cache */
-       sync
-       isync
-       ori     r0,r0,L3CR_L3HWF
-       sync
-       mtspr   SPRN_L3CR,r0    /* set the hardware flush bit */
-5:     mfspr   r0,SPRN_L3CR    /* wait for it to go to zero */
-       andi.   r0,r0,L3CR_L3HWF
-       bne     5b
-       rlwinm  r3,r3,0,~L3CR_L3E
-       sync
-       mtspr   SPRN_L3CR,r3    /* disable the L3 cache */
-       sync
-       ori     r4,r3,L3CR_L3I
-       mtspr   SPRN_L3CR,r4
-1:     mfspr   r4,SPRN_L3CR
-       andi.   r0,r4,L3CR_L3I
-       bne     1b
-       sync
-END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
-
-6:     mfspr   r0,SPRN_HID0    /* now disable the L1 data cache */
-       rlwinm  r0,r0,0,~HID0_DCE
-       mtspr   SPRN_HID0,r0
-       sync
-       isync
-       mtmsr   r11             /* restore DR and EE */
-       isync
-       blr
-#endif /* CONFIG_6xx */
diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c
deleted file mode 100644 (file)
index fba7e4d..0000000
+++ /dev/null
@@ -1,735 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_cpufreq.c
- *
- *  Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
- *  Copyright (C) 2004        John Steele Scott <toojays@toojays.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: Need a big cleanup here. Basically, we need to have different
- * cpufreq_driver structures for the different type of HW instead of the
- * current mess. We also need to better deal with the detection of the
- * type of machine.
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/slab.h>
-#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>
-#include <asm/irq.h>
-#include <asm/pmac_feature.h>
-#include <asm/mmu_context.h>
-#include <asm/sections.h>
-#include <asm/cputable.h>
-#include <asm/time.h>
-#include <asm/system.h>
-#include <asm/open_pic.h>
-#include <asm/keylargo.h>
-
-/* WARNING !!! This will cause calibrate_delay() to be called,
- * but this is an __init function ! So you MUST go edit
- * init/main.c to make it non-init before enabling DEBUG_FREQ
- */
-#undef DEBUG_FREQ
-
-/*
- * There is a problem with the core cpufreq code on SMP kernels,
- * it won't recalculate the Bogomips properly
- */
-#ifdef CONFIG_SMP
-#warning "WARNING, CPUFREQ not recommended on SMP kernels"
-#endif
-
-extern void low_choose_7447a_dfs(int dfs);
-extern void low_choose_750fx_pll(int pll);
-extern void low_sleep_handler(void);
-
-/*
- * Currently, PowerMac cpufreq supports only high & low frequencies
- * that are set by the firmware
- */
-static unsigned int low_freq;
-static unsigned int hi_freq;
-static unsigned int cur_freq;
-static unsigned int sleep_freq;
-
-/*
- * Different models uses different mecanisms to switch the frequency
- */
-static int (*set_speed_proc)(int low_speed);
-static unsigned int (*get_speed_proc)(void);
-
-/*
- * Some definitions used by the various speedprocs
- */
-static u32 voltage_gpio;
-static u32 frequency_gpio;
-static u32 slew_done_gpio;
-static int no_schedule;
-static int has_cpu_l2lve;
-static int is_pmu_based;
-
-/* There are only two frequency states for each processor. Values
- * are in kHz for the time being.
- */
-#define CPUFREQ_HIGH                  0
-#define CPUFREQ_LOW                   1
-
-static struct cpufreq_frequency_table pmac_cpu_freqs[] = {
-       {CPUFREQ_HIGH,          0},
-       {CPUFREQ_LOW,           0},
-       {0,                     CPUFREQ_TABLE_END},
-};
-
-static struct freq_attr* pmac_cpu_freqs_attr[] = {
-       &cpufreq_freq_attr_scaling_available_freqs,
-       NULL,
-};
-
-static inline void local_delay(unsigned long ms)
-{
-       if (no_schedule)
-               mdelay(ms);
-       else
-               msleep(ms);
-}
-
-static inline void wakeup_decrementer(void)
-{
-       set_dec(tb_ticks_per_jiffy);
-       /* No currently-supported powerbook has a 601,
-        * so use get_tbl, not native
-        */
-       last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
-}
-
-#ifdef DEBUG_FREQ
-static inline void debug_calc_bogomips(void)
-{
-       /* This will cause a recalc of bogomips and display the
-        * result. We backup/restore the value to avoid affecting the
-        * core cpufreq framework's own calculation.
-        */
-       extern void calibrate_delay(void);
-
-       unsigned long save_lpj = loops_per_jiffy;
-       calibrate_delay();
-       loops_per_jiffy = save_lpj;
-}
-#endif /* DEBUG_FREQ */
-
-/* Switch CPU speed under 750FX CPU control
- */
-static int cpu_750fx_cpu_speed(int low_speed)
-{
-       u32 hid2;
-
-       if (low_speed == 0) {
-               /* ramping up, set voltage first */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
-               /* Make sure we sleep for at least 1ms */
-               local_delay(10);
-
-               /* tweak L2 for high voltage */
-               if (has_cpu_l2lve) {
-                       hid2 = mfspr(SPRN_HID2);
-                       hid2 &= ~0x2000;
-                       mtspr(SPRN_HID2, hid2);
-               }
-       }
-#ifdef CONFIG_6xx
-       low_choose_750fx_pll(low_speed);
-#endif
-       if (low_speed == 1) {
-               /* tweak L2 for low voltage */
-               if (has_cpu_l2lve) {
-                       hid2 = mfspr(SPRN_HID2);
-                       hid2 |= 0x2000;
-                       mtspr(SPRN_HID2, hid2);
-               }
-
-               /* ramping down, set voltage last */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-               local_delay(10);
-       }
-
-       return 0;
-}
-
-static unsigned int cpu_750fx_get_cpu_speed(void)
-{
-       if (mfspr(SPRN_HID1) & HID1_PS)
-               return low_freq;
-       else
-               return hi_freq;
-}
-
-/* Switch CPU speed using DFS */
-static int dfs_set_cpu_speed(int low_speed)
-{
-       if (low_speed == 0) {
-               /* ramping up, set voltage first */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
-               /* Make sure we sleep for at least 1ms */
-               local_delay(1);
-       }
-
-       /* set frequency */
-#ifdef CONFIG_6xx
-       low_choose_7447a_dfs(low_speed);
-#endif
-       udelay(100);
-
-       if (low_speed == 1) {
-               /* ramping down, set voltage last */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-               local_delay(1);
-       }
-
-       return 0;
-}
-
-static unsigned int dfs_get_cpu_speed(void)
-{
-       if (mfspr(SPRN_HID1) & HID1_DFS)
-               return low_freq;
-       else
-               return hi_freq;
-}
-
-
-/* Switch CPU speed using slewing GPIOs
- */
-static int gpios_set_cpu_speed(int low_speed)
-{
-       int gpio, timeout = 0;
-
-       /* If ramping up, set voltage first */
-       if (low_speed == 0) {
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
-               /* Delay is way too big but it's ok, we schedule */
-               local_delay(10);
-       }
-
-       /* Set frequency */
-       gpio =  pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
-       if (low_speed == ((gpio & 0x01) == 0))
-               goto skip;
-
-       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio,
-                         low_speed ? 0x04 : 0x05);
-       udelay(200);
-       do {
-               if (++timeout > 100)
-                       break;
-               local_delay(1);
-               gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
-       } while((gpio & 0x02) == 0);
- skip:
-       /* If ramping down, set voltage last */
-       if (low_speed == 1) {
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
-               /* Delay is way too big but it's ok, we schedule */
-               local_delay(10);
-       }
-
-#ifdef DEBUG_FREQ
-       debug_calc_bogomips();
-#endif
-
-       return 0;
-}
-
-/* Switch CPU speed under PMU control
- */
-static int pmu_set_cpu_speed(int low_speed)
-{
-       struct adb_request req;
-       unsigned long save_l2cr;
-       unsigned long save_l3cr;
-       unsigned int pic_prio;
-       unsigned long flags;
-
-       preempt_disable();
-
-#ifdef DEBUG_FREQ
-       printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
-#endif
-       pmu_suspend();
-
-       /* Disable all interrupt sources on openpic */
-       pic_prio = openpic_get_priority();
-       openpic_set_priority(0xf);
-
-       /* Make sure the decrementer won't interrupt us */
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-       /* Make sure any pending DEC interrupt occuring while we did
-        * the above didn't re-enable the DEC */
-       mb();
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
-       /* We can now disable MSR_EE */
-       local_irq_save(flags);
-
-       /* Giveup the FPU & vec */
-       enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
-       if (cpu_has_feature(CPU_FTR_ALTIVEC))
-               enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
-       /* Save & disable L2 and L3 caches */
-       save_l3cr = _get_L3CR();        /* (returns -1 if not available) */
-       save_l2cr = _get_L2CR();        /* (returns -1 if not available) */
-
-       /* Send the new speed command. My assumption is that this command
-        * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep
-        */
-       pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed);
-       while (!req.complete)
-               pmu_poll();
-
-       /* Prepare the northbridge for the speed transition */
-       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1);
-
-       /* Call low level code to backup CPU state and recover from
-        * hardware reset
-        */
-       low_sleep_handler();
-
-       /* Restore the northbridge */
-       pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0);
-
-       /* Restore L2 cache */
-       if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
-               _set_L2CR(save_l2cr);
-       /* Restore L3 cache */
-       if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
-               _set_L3CR(save_l3cr);
-
-       /* Restore userland MMU context */
-       set_context(current->active_mm->context, current->active_mm->pgd);
-
-#ifdef DEBUG_FREQ
-       printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
-#endif
-
-       /* Restore low level PMU operations */
-       pmu_unlock();
-
-       /* Restore decrementer */
-       wakeup_decrementer();
-
-       /* Restore interrupts */
-       openpic_set_priority(pic_prio);
-
-       /* Let interrupts flow again ... */
-       local_irq_restore(flags);
-
-#ifdef DEBUG_FREQ
-       debug_calc_bogomips();
-#endif
-
-       pmu_resume();
-
-       preempt_enable();
-
-       return 0;
-}
-
-static int do_set_cpu_speed(int speed_mode, int notify)
-{
-       struct cpufreq_freqs freqs;
-       unsigned long l3cr;
-       static unsigned long prev_l3cr;
-
-       freqs.old = cur_freq;
-       freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
-       freqs.cpu = smp_processor_id();
-
-       if (freqs.old == freqs.new)
-               return 0;
-
-       if (notify)
-               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-       if (speed_mode == CPUFREQ_LOW &&
-           cpu_has_feature(CPU_FTR_L3CR)) {
-               l3cr = _get_L3CR();
-               if (l3cr & L3CR_L3E) {
-                       prev_l3cr = l3cr;
-                       _set_L3CR(0);
-               }
-       }
-       set_speed_proc(speed_mode == CPUFREQ_LOW);
-       if (speed_mode == CPUFREQ_HIGH &&
-           cpu_has_feature(CPU_FTR_L3CR)) {
-               l3cr = _get_L3CR();
-               if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
-                       _set_L3CR(prev_l3cr);
-       }
-       if (notify)
-               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-       cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
-
-       return 0;
-}
-
-static unsigned int pmac_cpufreq_get_speed(unsigned int cpu)
-{
-       return cur_freq;
-}
-
-static int pmac_cpufreq_verify(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
-}
-
-static int pmac_cpufreq_target(        struct cpufreq_policy *policy,
-                                       unsigned int target_freq,
-                                       unsigned int relation)
-{
-       unsigned int    newstate = 0;
-
-       if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
-                       target_freq, relation, &newstate))
-               return -EINVAL;
-
-       return do_set_cpu_speed(newstate, 1);
-}
-
-unsigned int pmac_get_one_cpufreq(int i)
-{
-       /* Supports only one CPU for now */
-       return (i == 0) ? cur_freq : 0;
-}
-
-static int pmac_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 = cur_freq;
-
-       cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu);
-       return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs);
-}
-
-static u32 read_gpio(struct device_node *np)
-{
-       u32 *reg = (u32 *)get_property(np, "reg", NULL);
-       u32 offset;
-
-       if (reg == NULL)
-               return 0;
-       /* That works for all keylargos but shall be fixed properly
-        * some day... The problem is that it seems we can't rely
-        * on the "reg" property of the GPIO nodes, they are either
-        * relative to the base of KeyLargo or to the base of the
-        * GPIO space, and the device-tree doesn't help.
-        */
-       offset = *reg;
-       if (offset < KEYLARGO_GPIO_LEVELS0)
-               offset += KEYLARGO_GPIO_LEVELS0;
-       return offset;
-}
-
-static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
-{
-       /* Ok, this could be made a bit smarter, but let's be robust for now. We
-        * always force a speed change to high speed before sleep, to make sure
-        * we have appropriate voltage and/or bus speed for the wakeup process,
-        * and to make sure our loops_per_jiffies are "good enough", that is will
-        * not cause too short delays if we sleep in low speed and wake in high
-        * speed..
-        */
-       no_schedule = 1;
-       sleep_freq = cur_freq;
-       if (cur_freq == low_freq && !is_pmu_based)
-               do_set_cpu_speed(CPUFREQ_HIGH, 0);
-       return 0;
-}
-
-static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
-{
-       /* If we resume, first check if we have a get() function */
-       if (get_speed_proc)
-               cur_freq = get_speed_proc();
-       else
-               cur_freq = 0;
-
-       /* We don't, hrm... we don't really know our speed here, best
-        * is that we force a switch to whatever it was, which is
-        * probably high speed due to our suspend() routine
-        */
-       do_set_cpu_speed(sleep_freq == low_freq ?
-                        CPUFREQ_LOW : CPUFREQ_HIGH, 0);
-
-       no_schedule = 0;
-       return 0;
-}
-
-static struct cpufreq_driver pmac_cpufreq_driver = {
-       .verify         = pmac_cpufreq_verify,
-       .target         = pmac_cpufreq_target,
-       .get            = pmac_cpufreq_get_speed,
-       .init           = pmac_cpufreq_cpu_init,
-       .suspend        = pmac_cpufreq_suspend,
-       .resume         = pmac_cpufreq_resume,
-       .flags          = CPUFREQ_PM_NO_WARN,
-       .attr           = pmac_cpu_freqs_attr,
-       .name           = "powermac",
-       .owner          = THIS_MODULE,
-};
-
-
-static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
-{
-       struct device_node *volt_gpio_np = of_find_node_by_name(NULL,
-                                                               "voltage-gpio");
-       struct device_node *freq_gpio_np = of_find_node_by_name(NULL,
-                                                               "frequency-gpio");
-       struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL,
-                                                                    "slewing-done");
-       u32 *value;
-
-       /*
-        * Check to see if it's GPIO driven or PMU only
-        *
-        * The way we extract the GPIO address is slightly hackish, but it
-        * works well enough for now. We need to abstract the whole GPIO
-        * stuff sooner or later anyway
-        */
-
-       if (volt_gpio_np)
-               voltage_gpio = read_gpio(volt_gpio_np);
-       if (freq_gpio_np)
-               frequency_gpio = read_gpio(freq_gpio_np);
-       if (slew_done_gpio_np)
-               slew_done_gpio = read_gpio(slew_done_gpio_np);
-
-       /* If we use the frequency GPIOs, calculate the min/max speeds based
-        * on the bus frequencies
-        */
-       if (frequency_gpio && slew_done_gpio) {
-               int lenp, rc;
-               u32 *freqs, *ratio;
-
-               freqs = (u32 *)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 = (u32 *)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;
-               }
-
-               /* Get the min/max bus frequencies */
-               low_freq = min(freqs[0], freqs[1]);
-               hi_freq = max(freqs[0], freqs[1]);
-
-               /* Grrrr.. It _seems_ that the device-tree is lying on the low bus
-                * frequency, it claims it to be around 84Mhz on some models while
-                * it appears to be approx. 101Mhz on all. Let's hack around here...
-                * fortunately, we don't need to be too precise
-                */
-               if (low_freq < 98000000)
-                       low_freq = 101000000;
-                       
-               /* Convert those to CPU core clocks */
-               low_freq = (low_freq * (*ratio)) / 2000;
-               hi_freq = (hi_freq * (*ratio)) / 2000;
-
-               /* Now we get the frequencies, we read the GPIO to see what is out current
-                * speed
-                */
-               rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
-               cur_freq = (rc & 0x01) ? hi_freq : low_freq;
-
-               set_speed_proc = gpios_set_cpu_speed;
-               return 1;
-       }
-
-       /* If we use the PMU, look for the min & max frequencies in the
-        * device-tree
-        */
-       value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
-       if (!value)
-               return 1;
-       low_freq = (*value) / 1000;
-       /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree
-        * here */
-       if (low_freq < 100000)
-               low_freq *= 10;
-
-       value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL);
-       if (!value)
-               return 1;
-       hi_freq = (*value) / 1000;
-       set_speed_proc = pmu_set_cpu_speed;
-       is_pmu_based = 1;
-
-       return 0;
-}
-
-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)
-               return 1;
-
-       volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
-       if (volt_gpio_np)
-               voltage_gpio = read_gpio(volt_gpio_np);
-       if (!voltage_gpio){
-               printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n");
-               return 1;
-       }
-
-       /* OF only reports the high frequency */
-       hi_freq = cur_freq;
-       low_freq = cur_freq/2;
-
-       /* Read actual frequency from CPU */
-       cur_freq = dfs_get_cpu_speed();
-       set_speed_proc = dfs_set_cpu_speed;
-       get_speed_proc = dfs_get_cpu_speed;
-
-       return 0;
-}
-
-static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
-{
-       struct device_node *volt_gpio_np;
-       u32 pvr, *value;
-
-       if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
-               return 1;
-
-       hi_freq = cur_freq;
-       value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL);
-       if (!value)
-               return 1;
-       low_freq = (*value) / 1000;
-
-       volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
-       if (volt_gpio_np)
-               voltage_gpio = read_gpio(volt_gpio_np);
-
-       pvr = mfspr(SPRN_PVR);
-       has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
-
-       set_speed_proc = cpu_750fx_cpu_speed;
-       get_speed_proc = cpu_750fx_get_cpu_speed;
-       cur_freq = cpu_750fx_get_cpu_speed();
-
-       return 0;
-}
-
-/* Currently, we support the following machines:
- *
- *  - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
- *  - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
- *  - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz)
- *  - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
- *  - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz)
- *  - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
- *  - Recent MacRISC3 laptops
- *  - All new machines with 7447A CPUs
- */
-static int __init pmac_cpufreq_setup(void)
-{
-       struct device_node      *cpunode;
-       u32                     *value;
-
-       if (strstr(cmd_line, "nocpufreq"))
-               return 0;
-
-       /* Assume only one CPU */
-       cpunode = find_type_devices("cpu");
-       if (!cpunode)
-               goto out;
-
-       /* Get current cpu clock freq */
-       value = (u32 *)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) &&
-           PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
-               pmac_cpufreq_init_7447A(cpunode);
-       /* Check for other MacRISC3 machines */
-       } else if (machine_is_compatible("PowerBook3,4") ||
-                  machine_is_compatible("PowerBook3,5") ||
-                  machine_is_compatible("MacRISC3")) {
-               pmac_cpufreq_init_MacRISC3(cpunode);
-       /* Else check for iBook2 500/600 */
-       } else if (machine_is_compatible("PowerBook4,1")) {
-               hi_freq = cur_freq;
-               low_freq = 400000;
-               set_speed_proc = pmu_set_cpu_speed;
-               is_pmu_based = 1;
-       }
-       /* Else check for TiPb 550 */
-       else if (machine_is_compatible("PowerBook3,3") && cur_freq == 550000) {
-               hi_freq = cur_freq;
-               low_freq = 500000;
-               set_speed_proc = pmu_set_cpu_speed;
-               is_pmu_based = 1;
-       }
-       /* Else check for TiPb 400 & 500 */
-       else if (machine_is_compatible("PowerBook3,2")) {
-               /* We only know about the 400 MHz and the 500Mhz model
-                * they both have 300 MHz as low frequency
-                */
-               if (cur_freq < 350000 || cur_freq > 550000)
-                       goto out;
-               hi_freq = cur_freq;
-               low_freq = 300000;
-               set_speed_proc = pmu_set_cpu_speed;
-               is_pmu_based = 1;
-       }
-       /* Else check for 750FX */
-       else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
-               pmac_cpufreq_init_750FX(cpunode);
-out:
-       if (set_speed_proc == NULL)
-               return -ENODEV;
-
-       pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
-       pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
-
-       printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
-       printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
-              low_freq/1000, hi_freq/1000, cur_freq/1000);
-
-       return cpufreq_register_driver(&pmac_cpufreq_driver);
-}
-
-module_init(pmac_cpufreq_setup);
-
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
deleted file mode 100644 (file)
index 6b7b3a1..0000000
+++ /dev/null
@@ -1,3023 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_feature.c
- *
- *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
- *                          Ben. 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 Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- *  TODO:
- *
- *   - Replace mdelay with some schedule loop if possible
- *   - Shorten some obfuscated delays on some routines (like modem
- *     power)
- *   - Refcount some clocks (see darwin)
- *   - Split split split...
- *
- */
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <asm/sections.h>
-#include <asm/errno.h>
-#include <asm/ohare.h>
-#include <asm/heathrow.h>
-#include <asm/keylargo.h>
-#include <asm/uninorth.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/dbdma.h>
-#include <asm/pci-bridge.h>
-#include <asm/pmac_low_i2c.h>
-
-#undef DEBUG_FEATURE
-
-#ifdef DEBUG_FEATURE
-#define DBG(fmt,...) printk(KERN_DEBUG fmt)
-#else
-#define DBG(fmt,...)
-#endif
-
-#ifdef CONFIG_6xx
-extern int powersave_lowspeed;
-#endif
-
-extern int powersave_nap;
-extern struct device_node *k2_skiplist[2];
-
-
-/*
- * We use a single global lock to protect accesses. Each driver has
- * to take care of its own locking
- */
-static DEFINE_SPINLOCK(feature_lock);
-
-#define LOCK(flags)    spin_lock_irqsave(&feature_lock, flags);
-#define UNLOCK(flags)  spin_unlock_irqrestore(&feature_lock, flags);
-
-
-/*
- * Instance of some macio stuffs
- */
-struct macio_chip macio_chips[MAX_MACIO_CHIPS];
-
-struct macio_chip* macio_find(struct device_node* child, int type)
-{
-       while(child) {
-               int     i;
-
-               for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
-                       if (child == macio_chips[i].of_node &&
-                           (!type || macio_chips[i].type == type))
-                               return &macio_chips[i];
-               child = child->parent;
-       }
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(macio_find);
-
-static const char* macio_names[] =
-{
-       "Unknown",
-       "Grand Central",
-       "OHare",
-       "OHareII",
-       "Heathrow",
-       "Gatwick",
-       "Paddington",
-       "Keylargo",
-       "Pangea",
-       "Intrepid",
-       "K2"
-};
-
-
-
-/*
- * Uninorth reg. access. Note that Uni-N regs are big endian
- */
-
-#define UN_REG(r)      (uninorth_base + ((r) >> 2))
-#define UN_IN(r)       (in_be32(UN_REG(r)))
-#define UN_OUT(r,v)    (out_be32(UN_REG(r), (v)))
-#define UN_BIS(r,v)    (UN_OUT((r), UN_IN(r) | (v)))
-#define UN_BIC(r,v)    (UN_OUT((r), UN_IN(r) & ~(v)))
-
-static struct device_node* uninorth_node;
-static u32 __iomem * uninorth_base;
-static u32 uninorth_rev;
-static int uninorth_u3;
-static void __iomem *u3_ht;
-
-/*
- * For each motherboard family, we have a table of functions pointers
- * that handle the various features.
- */
-
-typedef long (*feature_call)(struct device_node* node, long param, long value);
-
-struct feature_table_entry {
-       unsigned int    selector;
-       feature_call    function;
-};
-
-struct pmac_mb_def
-{
-       const char*                     model_string;
-       const char*                     model_name;
-       int                             model_id;
-       struct feature_table_entry*     features;
-       unsigned long                   board_flags;
-};
-static struct pmac_mb_def pmac_mb;
-
-/*
- * Here are the chip specific feature functions
- */
-
-static inline int
-simple_feature_tweak(struct device_node* node, int type, int reg, u32 mask, int value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, type);
-       if (!macio)
-               return -ENODEV;
-       LOCK(flags);
-       if (value)
-               MACIO_BIS(reg, mask);
-       else
-               MACIO_BIC(reg, mask);
-       (void)MACIO_IN32(reg);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-#ifndef CONFIG_POWER4
-
-static long
-ohare_htw_scc_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           chan_mask;
-       unsigned long           fcr;
-       unsigned long           flags;
-       int                     htw, trans;
-       unsigned long           rmask;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (!strcmp(node->name, "ch-a"))
-               chan_mask = MACIO_FLAG_SCCA_ON;
-       else if (!strcmp(node->name, "ch-b"))
-               chan_mask = MACIO_FLAG_SCCB_ON;
-       else
-               return -ENODEV;
-
-       htw = (macio->type == macio_heathrow || macio->type == macio_paddington
-               || macio->type == macio_gatwick);
-       /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */
-       trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-                pmac_mb.model_id != PMAC_TYPE_YIKES);
-       if (value) {
-#ifdef CONFIG_ADB_PMU
-               if ((param & 0xfff) == PMAC_SCC_IRDA)
-                       pmu_enable_irled(1);
-#endif /* CONFIG_ADB_PMU */
-               LOCK(flags);
-               fcr = MACIO_IN32(OHARE_FCR);
-               /* Check if scc cell need enabling */
-               if (!(fcr & OH_SCC_ENABLE)) {
-                       fcr |= OH_SCC_ENABLE;
-                       if (htw) {
-                               /* Side effect: this will also power up the
-                                * modem, but it's too messy to figure out on which
-                                * ports this controls the tranceiver and on which
-                                * it controls the modem
-                                */
-                               if (trans)
-                                       fcr &= ~HRW_SCC_TRANS_EN_N;
-                               MACIO_OUT32(OHARE_FCR, fcr);
-                               fcr |= (rmask = HRW_RESET_SCC);
-                               MACIO_OUT32(OHARE_FCR, fcr);
-                       } else {
-                               fcr |= (rmask = OH_SCC_RESET);
-                               MACIO_OUT32(OHARE_FCR, fcr);
-                       }
-                       UNLOCK(flags);
-                       (void)MACIO_IN32(OHARE_FCR);
-                       mdelay(15);
-                       LOCK(flags);
-                       fcr &= ~rmask;
-                       MACIO_OUT32(OHARE_FCR, fcr);
-               }
-               if (chan_mask & MACIO_FLAG_SCCA_ON)
-                       fcr |= OH_SCCA_IO;
-               if (chan_mask & MACIO_FLAG_SCCB_ON)
-                       fcr |= OH_SCCB_IO;
-               MACIO_OUT32(OHARE_FCR, fcr);
-               macio->flags |= chan_mask;
-               UNLOCK(flags);
-               if (param & PMAC_SCC_FLAG_XMON)
-                       macio->flags |= MACIO_FLAG_SCC_LOCKED;
-       } else {
-               if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-                       return -EPERM;
-               LOCK(flags);
-               fcr = MACIO_IN32(OHARE_FCR);
-               if (chan_mask & MACIO_FLAG_SCCA_ON)
-                       fcr &= ~OH_SCCA_IO;
-               if (chan_mask & MACIO_FLAG_SCCB_ON)
-                       fcr &= ~OH_SCCB_IO;
-               MACIO_OUT32(OHARE_FCR, fcr);
-               if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {
-                       fcr &= ~OH_SCC_ENABLE;
-                       if (htw && trans)
-                               fcr |= HRW_SCC_TRANS_EN_N;
-                       MACIO_OUT32(OHARE_FCR, fcr);
-               }
-               macio->flags &= ~(chan_mask);
-               UNLOCK(flags);
-               mdelay(10);
-#ifdef CONFIG_ADB_PMU
-               if ((param & 0xfff) == PMAC_SCC_IRDA)
-                       pmu_enable_irled(0);
-#endif /* CONFIG_ADB_PMU */
-       }
-       return 0;
-}
-
-static long
-ohare_floppy_enable(struct device_node* node, long param, long value)
-{
-       return simple_feature_tweak(node, macio_ohare,
-               OHARE_FCR, OH_FLOPPY_ENABLE, value);
-}
-
-static long
-ohare_mesh_enable(struct device_node* node, long param, long value)
-{
-       return simple_feature_tweak(node, macio_ohare,
-               OHARE_FCR, OH_MESH_ENABLE, value);
-}
-
-static long
-ohare_ide_enable(struct device_node* node, long param, long value)
-{
-       switch(param) {
-           case 0:
-               /* For some reason, setting the bit in set_initial_features()
-                * doesn't stick. I'm still investigating... --BenH.
-                */
-               if (value)
-                       simple_feature_tweak(node, macio_ohare,
-                               OHARE_FCR, OH_IOBUS_ENABLE, 1);
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_IDE0_ENABLE, value);
-           case 1:
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_BAY_IDE_ENABLE, value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-ohare_ide_reset(struct device_node* node, long param, long value)
-{
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_IDE0_RESET_N, !value);
-           case 1:
-               return simple_feature_tweak(node, macio_ohare,
-                       OHARE_FCR, OH_IDE1_RESET_N, !value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-ohare_sleep_state(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio = &macio_chips[0];
-
-       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-               return -EPERM;
-       if (value == 1) {
-               MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);
-       } else if (value == 0) {
-               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-       }
-
-       return 0;
-}
-
-static long
-heathrow_modem_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       u8                      gpio;
-       unsigned long           flags;
-
-       macio = macio_find(node, macio_unknown);
-       if (!macio)
-               return -ENODEV;
-       gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;
-       if (!value) {
-               LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-               UNLOCK(flags);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               mdelay(250);
-       }
-       if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&
-           pmac_mb.model_id != PMAC_TYPE_YIKES) {
-               LOCK(flags);
-               if (value)
-                       MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-               else
-                       MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-               mdelay(250);
-       }
-       if (value) {
-               LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);
-               (void)MACIO_IN8(HRW_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250);
-       }
-       return 0;
-}
-
-static long
-heathrow_floppy_enable(struct device_node* node, long param, long value)
-{
-       return simple_feature_tweak(node, macio_unknown,
-               HEATHROW_FCR,
-               HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,
-               value);
-}
-
-static long
-heathrow_mesh_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, macio_unknown);
-       if (!macio)
-               return -ENODEV;
-       LOCK(flags);
-       /* Set clear mesh cell enable */
-       if (value)
-               MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);
-       else
-               MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
-       (void)MACIO_IN32(HEATHROW_FCR);
-       udelay(10);
-       /* Set/Clear termination power */
-       if (value)
-               MACIO_BIC(HEATHROW_MBCR, 0x04000000);
-       else
-               MACIO_BIS(HEATHROW_MBCR, 0x04000000);
-       (void)MACIO_IN32(HEATHROW_MBCR);
-       udelay(10);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-static long
-heathrow_ide_enable(struct device_node* node, long param, long value)
-{
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_IDE0_ENABLE, value);
-           case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-heathrow_ide_reset(struct device_node* node, long param, long value)
-{
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_IDE0_RESET_N, !value);
-           case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       HEATHROW_FCR, HRW_IDE1_RESET_N, !value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-heathrow_bmac_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (value) {
-               LOCK(flags);
-               MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-               MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-               mdelay(10);
-               LOCK(flags);
-               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-               mdelay(10);
-       } else {
-               LOCK(flags);
-               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);
-               UNLOCK(flags);
-       }
-       return 0;
-}
-
-static long
-heathrow_sound_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       /* B&W G3 and Yikes don't support that properly (the
-        * sound appear to never come back after beeing shut down).
-        */
-       if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||
-           pmac_mb.model_id == PMAC_TYPE_YIKES)
-               return 0;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (value) {
-               LOCK(flags);
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-               UNLOCK(flags);
-               (void)MACIO_IN32(HEATHROW_FCR);
-       } else {
-               LOCK(flags);
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               UNLOCK(flags);
-       }
-       return 0;
-}
-
-static u32 save_fcr[6];
-static u32 save_mbcr;
-static u32 save_gpio_levels[2];
-static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
-static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
-static u32 save_unin_clock_ctl;
-static struct dbdma_regs save_dbdma[13];
-static struct dbdma_regs save_alt_dbdma[13];
-
-static void
-dbdma_save(struct macio_chip* macio, struct dbdma_regs* save)
-{
-       int i;
-
-       /* Save state & config of DBDMA channels */
-       for (i=0; i<13; i++) {
-               volatile struct dbdma_regs __iomem * chan = (void __iomem *)
-                       (macio->base + ((0x8000+i*0x100)>>2));
-               save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);
-               save[i].cmdptr = in_le32(&chan->cmdptr);
-               save[i].intr_sel = in_le32(&chan->intr_sel);
-               save[i].br_sel = in_le32(&chan->br_sel);
-               save[i].wait_sel = in_le32(&chan->wait_sel);
-       }
-}
-
-static void
-dbdma_restore(struct macio_chip* macio, struct dbdma_regs* save)
-{
-       int i;
-
-       /* Save state & config of DBDMA channels */
-       for (i=0; i<13; i++) {
-               volatile struct dbdma_regs __iomem * chan = (void __iomem *)
-                       (macio->base + ((0x8000+i*0x100)>>2));
-               out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);
-               while (in_le32(&chan->status) & ACTIVE)
-                       mb();
-               out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);
-               out_le32(&chan->cmdptr, save[i].cmdptr);
-               out_le32(&chan->intr_sel, save[i].intr_sel);
-               out_le32(&chan->br_sel, save[i].br_sel);
-               out_le32(&chan->wait_sel, save[i].wait_sel);
-       }
-}
-
-static void
-heathrow_sleep(struct macio_chip* macio, int secondary)
-{
-       if (secondary) {
-               dbdma_save(macio, save_alt_dbdma);
-               save_fcr[2] = MACIO_IN32(0x38);
-               save_fcr[3] = MACIO_IN32(0x3c);
-       } else {
-               dbdma_save(macio, save_dbdma);
-               save_fcr[0] = MACIO_IN32(0x38);
-               save_fcr[1] = MACIO_IN32(0x3c);
-               save_mbcr = MACIO_IN32(0x34);
-               /* Make sure sound is shut down */
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               /* This seems to be necessary as well or the fan
-                * keeps coming up and battery drains fast */
-               MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);
-               MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);
-               /* Make sure eth is down even if module or sleep
-                * won't work properly */
-               MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);
-       }
-       /* Make sure modem is shut down */
-       MACIO_OUT8(HRW_GPIO_MODEM_RESET,
-               MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);
-       MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);
-       MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);
-
-       /* Let things settle */
-       (void)MACIO_IN32(HEATHROW_FCR);
-}
-
-static void
-heathrow_wakeup(struct macio_chip* macio, int secondary)
-{
-       if (secondary) {
-               MACIO_OUT32(0x38, save_fcr[2]);
-               (void)MACIO_IN32(0x38);
-               mdelay(1);
-               MACIO_OUT32(0x3c, save_fcr[3]);
-               (void)MACIO_IN32(0x38);
-               mdelay(10);
-               dbdma_restore(macio, save_alt_dbdma);
-       } else {
-               MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);
-               (void)MACIO_IN32(0x38);
-               mdelay(1);
-               MACIO_OUT32(0x3c, save_fcr[1]);
-               (void)MACIO_IN32(0x38);
-               mdelay(1);
-               MACIO_OUT32(0x34, save_mbcr);
-               (void)MACIO_IN32(0x38);
-               mdelay(10);
-               dbdma_restore(macio, save_dbdma);
-       }
-}
-
-static long
-heathrow_sleep_state(struct device_node* node, long param, long value)
-{
-       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-               return -EPERM;
-       if (value == 1) {
-               if (macio_chips[1].type == macio_gatwick)
-                       heathrow_sleep(&macio_chips[0], 1);
-               heathrow_sleep(&macio_chips[0], 0);
-       } else if (value == 0) {
-               heathrow_wakeup(&macio_chips[0], 0);
-               if (macio_chips[1].type == macio_gatwick)
-                       heathrow_wakeup(&macio_chips[0], 1);
-       }
-       return 0;
-}
-
-static long
-core99_scc_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-       unsigned long           chan_mask;
-       u32                     fcr;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       if (!strcmp(node->name, "ch-a"))
-               chan_mask = MACIO_FLAG_SCCA_ON;
-       else if (!strcmp(node->name, "ch-b"))
-               chan_mask = MACIO_FLAG_SCCB_ON;
-       else
-               return -ENODEV;
-
-       if (value) {
-               int need_reset_scc = 0;
-               int need_reset_irda = 0;
-
-               LOCK(flags);
-               fcr = MACIO_IN32(KEYLARGO_FCR0);
-               /* Check if scc cell need enabling */
-               if (!(fcr & KL0_SCC_CELL_ENABLE)) {
-                       fcr |= KL0_SCC_CELL_ENABLE;
-                       need_reset_scc = 1;
-               }
-               if (chan_mask & MACIO_FLAG_SCCA_ON) {
-                       fcr |= KL0_SCCA_ENABLE;
-                       /* Don't enable line drivers for I2S modem */
-                       if ((param & 0xfff) == PMAC_SCC_I2S1)
-                               fcr &= ~KL0_SCC_A_INTF_ENABLE;
-                       else
-                               fcr |= KL0_SCC_A_INTF_ENABLE;
-               }
-               if (chan_mask & MACIO_FLAG_SCCB_ON) {
-                       fcr |= KL0_SCCB_ENABLE;
-                       /* Perform irda specific inits */
-                       if ((param & 0xfff) == PMAC_SCC_IRDA) {
-                               fcr &= ~KL0_SCC_B_INTF_ENABLE;
-                               fcr |= KL0_IRDA_ENABLE;
-                               fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;
-                               fcr |= KL0_IRDA_SOURCE1_SEL;
-                               fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-                               fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-                               need_reset_irda = 1;
-                       } else
-                               fcr |= KL0_SCC_B_INTF_ENABLE;
-               }
-               MACIO_OUT32(KEYLARGO_FCR0, fcr);
-               macio->flags |= chan_mask;
-               if (need_reset_scc)  {
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       UNLOCK(flags);
-                       mdelay(15);
-                       LOCK(flags);
-                       MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);
-               }
-               if (need_reset_irda)  {
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       UNLOCK(flags);
-                       mdelay(15);
-                       LOCK(flags);
-                       MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);
-               }
-               UNLOCK(flags);
-               if (param & PMAC_SCC_FLAG_XMON)
-                       macio->flags |= MACIO_FLAG_SCC_LOCKED;
-       } else {
-               if (macio->flags & MACIO_FLAG_SCC_LOCKED)
-                       return -EPERM;
-               LOCK(flags);
-               fcr = MACIO_IN32(KEYLARGO_FCR0);
-               if (chan_mask & MACIO_FLAG_SCCA_ON)
-                       fcr &= ~KL0_SCCA_ENABLE;
-               if (chan_mask & MACIO_FLAG_SCCB_ON) {
-                       fcr &= ~KL0_SCCB_ENABLE;
-                       /* Perform irda specific clears */
-                       if ((param & 0xfff) == PMAC_SCC_IRDA) {
-                               fcr &= ~KL0_IRDA_ENABLE;
-                               fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
-                               fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);
-                               fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);
-                       }
-               }
-               MACIO_OUT32(KEYLARGO_FCR0, fcr);
-               if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {
-                       fcr &= ~KL0_SCC_CELL_ENABLE;
-                       MACIO_OUT32(KEYLARGO_FCR0, fcr);
-               }
-               macio->flags &= ~(chan_mask);
-               UNLOCK(flags);
-               mdelay(10);
-       }
-       return 0;
-}
-
-static long
-core99_modem_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       u8                      gpio;
-       unsigned long           flags;
-
-       /* Hack for internal USB modem */
-       if (node == NULL) {
-               if (macio_chips[0].type != macio_keylargo)
-                       return -ENODEV;
-               node = macio_chips[0].of_node;
-       }
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-       gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-       gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-
-       if (!value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               UNLOCK(flags);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               mdelay(250);
-       }
-       LOCK(flags);
-       if (value) {
-               MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-               UNLOCK(flags);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               mdelay(250);
-       } else {
-               MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-               UNLOCK(flags);
-       }
-       if (value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250);
-       }
-       return 0;
-}
-
-static long
-pangea_modem_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       u8                      gpio;
-       unsigned long           flags;
-
-       /* Hack for internal USB modem */
-       if (node == NULL) {
-               if (macio_chips[0].type != macio_pangea &&
-                   macio_chips[0].type != macio_intrepid)
-                       return -ENODEV;
-               node = macio_chips[0].of_node;
-       }
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-       gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);
-       gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;
-       gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;
-
-       if (!value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               UNLOCK(flags);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               mdelay(250);
-       }
-       LOCK(flags);
-       if (value) {
-               MACIO_OUT8(KL_GPIO_MODEM_POWER,
-                       KEYLARGO_GPIO_OUTPUT_ENABLE);
-               UNLOCK(flags);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               mdelay(250);
-       } else {
-               MACIO_OUT8(KL_GPIO_MODEM_POWER,
-                       KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-               UNLOCK(flags);
-       }
-       if (value) {
-               LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250); LOCK(flags);
-               MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);
-               (void)MACIO_IN8(KL_GPIO_MODEM_RESET);
-               UNLOCK(flags); mdelay(250);
-       }
-       return 0;
-}
-
-static long
-core99_ata100_enable(struct device_node* node, long value)
-{
-       unsigned long flags;
-       struct pci_dev *pdev = NULL;
-       u8 pbus, pid;
-
-       if (uninorth_rev < 0x24)
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value)
-               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
-       else
-               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);
-       (void)UN_IN(UNI_N_CLOCK_CNTL);
-       UNLOCK(flags);
-       udelay(20);
-
-       if (value) {
-               if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
-                       pdev = pci_find_slot(pbus, pid);
-               if (pdev == NULL)
-                       return 0;
-               pci_enable_device(pdev);
-               pci_set_master(pdev);
-       }
-       return 0;
-}
-
-static long
-core99_ide_enable(struct device_node* node, long param, long value)
-{
-       /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
-        * based ata-100
-        */
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);
-           case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);
-           case 2:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);
-           case 3:
-               return core99_ata100_enable(node, value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-core99_ide_reset(struct device_node* node, long param, long value)
-{
-       switch(param) {
-           case 0:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);
-           case 1:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);
-           case 2:
-               return simple_feature_tweak(node, macio_unknown,
-                       KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);
-           default:
-               return -ENODEV;
-       }
-}
-
-static long
-core99_gmac_enable(struct device_node* node, long param, long value)
-{
-       unsigned long flags;
-
-       LOCK(flags);
-       if (value)
-               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-       else
-               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-       (void)UN_IN(UNI_N_CLOCK_CNTL);
-       UNLOCK(flags);
-       udelay(20);
-
-       return 0;
-}
-
-static long
-core99_gmac_phy_reset(struct device_node* node, long param, long value)
-{
-       unsigned long flags;
-       struct macio_chip* macio;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       LOCK(flags);
-       MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
-       (void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);
-       UNLOCK(flags);
-       mdelay(10);
-       LOCK(flags);
-       MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
-               KEYLARGO_GPIO_OUTOUT_DATA);
-       UNLOCK(flags);
-       mdelay(10);
-
-       return 0;
-}
-
-static long
-core99_sound_chip_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-
-       /* Do a better probe code, screamer G4 desktops &
-        * iMacs can do that too, add a recalibrate  in
-        * the driver as well
-        */
-       if (pmac_mb.model_id == PMAC_TYPE_PISMO ||
-           pmac_mb.model_id == PMAC_TYPE_TITANIUM) {
-               LOCK(flags);
-               if (value)
-                       MACIO_OUT8(KL_GPIO_SOUND_POWER,
-                               KEYLARGO_GPIO_OUTPUT_ENABLE |
-                               KEYLARGO_GPIO_OUTOUT_DATA);
-               else
-                       MACIO_OUT8(KL_GPIO_SOUND_POWER,
-                               KEYLARGO_GPIO_OUTPUT_ENABLE);
-               (void)MACIO_IN8(KL_GPIO_SOUND_POWER);
-               UNLOCK(flags);
-       }
-       return 0;
-}
-
-static long
-core99_airport_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip*      macio;
-       unsigned long           flags;
-       int                     state;
-
-       macio = macio_find(node, 0);
-       if (!macio)
-               return -ENODEV;
-
-       /* Hint: we allow passing of macio itself for the sake of the
-        * sleep code
-        */
-       if (node != macio->of_node &&
-           (!node->parent || node->parent != macio->of_node))
-               return -ENODEV;
-       state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;
-       if (value == state)
-               return 0;
-       if (value) {
-               /* This code is a reproduction of OF enable-cardslot
-                * and init-wireless methods, slightly hacked until
-                * I got it working.
-                */
-               LOCK(flags);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-               UNLOCK(flags);
-               mdelay(10);
-               LOCK(flags);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);
-               UNLOCK(flags);
-
-               mdelay(10);
-
-               LOCK(flags);
-               MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
-               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);
-               udelay(10);
-               MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);
-               (void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);
-               UNLOCK(flags);
-               udelay(10);
-               MACIO_OUT32(0x1c000, 0);
-               mdelay(1);
-               MACIO_OUT8(0x1a3e0, 0x41);
-               (void)MACIO_IN8(0x1a3e0);
-               udelay(10);
-               LOCK(flags);
-               MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               UNLOCK(flags);
-               mdelay(100);
-
-               macio->flags |= MACIO_FLAG_AIRPORT_ON;
-       } else {
-               LOCK(flags);
-               MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);
-               (void)MACIO_IN32(KEYLARGO_FCR2);
-               MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);
-               MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);
-               (void)MACIO_IN8(KL_GPIO_AIRPORT_4);
-               UNLOCK(flags);
-
-               macio->flags &= ~MACIO_FLAG_AIRPORT_ON;
-       }
-       return 0;
-}
-
-#ifdef CONFIG_SMP
-static long
-core99_reset_cpu(struct device_node* node, long param, long value)
-{
-       unsigned int reset_io = 0;
-       unsigned long flags;
-       struct macio_chip* macio;
-       struct device_node* np;
-       const int dflt_reset_lines[] = {        KL_GPIO_RESET_CPU0,
-                                               KL_GPIO_RESET_CPU1,
-                                               KL_GPIO_RESET_CPU2,
-                                               KL_GPIO_RESET_CPU3 };
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo)
-               return -ENODEV;
-
-       np = find_path_device("/cpus");
-       if (np == NULL)
-               return -ENODEV;
-       for (np = np->child; np != NULL; np = np->sibling) {
-               u32* num = (u32 *)get_property(np, "reg", NULL);
-               u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
-               if (num == NULL || rst == NULL)
-                       continue;
-               if (param == *num) {
-                       reset_io = *rst;
-                       break;
-               }
-       }
-       if (np == NULL || reset_io == 0)
-               reset_io = dflt_reset_lines[param];
-
-       LOCK(flags);
-       MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-       (void)MACIO_IN8(reset_io);
-       udelay(1);
-       MACIO_OUT8(reset_io, 0);
-       (void)MACIO_IN8(reset_io);
-       UNLOCK(flags);
-
-       return 0;
-}
-#endif /* CONFIG_SMP */
-
-static long
-core99_usb_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip* macio;
-       unsigned long flags;
-       char* prop;
-       int number;
-       u32 reg;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       prop = (char *)get_property(node, "AAPL,clock-id", NULL);
-       if (!prop)
-               return -ENODEV;
-       if (strncmp(prop, "usb0u048", 8) == 0)
-               number = 0;
-       else if (strncmp(prop, "usb1u148", 8) == 0)
-               number = 2;
-       else if (strncmp(prop, "usb2u248", 8) == 0)
-               number = 4;
-       else
-               return -ENODEV;
-
-       /* Sorry for the brute-force locking, but this is only used during
-        * sleep and the timing seem to be critical
-        */
-       LOCK(flags);
-       if (value) {
-               /* Turn ON */
-               if (number == 0) {
-                       MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       UNLOCK(flags);
-                       mdelay(1);
-                       LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-               } else if (number == 2) {
-                       MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-                       UNLOCK(flags);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       mdelay(1);
-                       LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-               } else if (number == 4) {
-                       MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
-                       UNLOCK(flags);
-                       (void)MACIO_IN32(KEYLARGO_FCR1);
-                       mdelay(1);
-                       LOCK(flags);
-                       MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
-               }
-               if (number < 4) {
-                       reg = MACIO_IN32(KEYLARGO_FCR4);
-                       reg &=  ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-                               KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
-                       reg &=  ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-                               KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
-                       MACIO_OUT32(KEYLARGO_FCR4, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR4);
-                       udelay(10);
-               } else {
-                       reg = MACIO_IN32(KEYLARGO_FCR3);
-                       reg &=  ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
-                       reg &=  ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
-                       MACIO_OUT32(KEYLARGO_FCR3, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR3);
-                       udelay(10);
-               }
-               if (macio->type == macio_intrepid) {
-                       /* wait for clock stopped bits to clear */
-                       u32 test0 = 0, test1 = 0;
-                       u32 status0, status1;
-                       int timeout = 1000;
-
-                       UNLOCK(flags);
-                       switch (number) {
-                       case 0:
-                               test0 = UNI_N_CLOCK_STOPPED_USB0;
-                               test1 = UNI_N_CLOCK_STOPPED_USB0PCI;
-                               break;
-                       case 2:
-                               test0 = UNI_N_CLOCK_STOPPED_USB1;
-                               test1 = UNI_N_CLOCK_STOPPED_USB1PCI;
-                               break;
-                       case 4:
-                               test0 = UNI_N_CLOCK_STOPPED_USB2;
-                               test1 = UNI_N_CLOCK_STOPPED_USB2PCI;
-                               break;
-                       }
-                       do {
-                               if (--timeout <= 0) {
-                                       printk(KERN_ERR "core99_usb_enable: "
-                                              "Timeout waiting for clocks\n");
-                                       break;
-                               }
-                               mdelay(1);
-                               status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);
-                               status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);
-                       } while ((status0 & test0) | (status1 & test1));
-                       LOCK(flags);
-               }
-       } else {
-               /* Turn OFF */
-               if (number < 4) {
-                       reg = MACIO_IN32(KEYLARGO_FCR4);
-                       reg |=  KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-                               KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
-                       reg |=  KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-                               KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
-                       MACIO_OUT32(KEYLARGO_FCR4, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR4);
-                       udelay(1);
-               } else {
-                       reg = MACIO_IN32(KEYLARGO_FCR3);
-                       reg |=  KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
-                       reg |=  KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
-                               KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
-                       MACIO_OUT32(KEYLARGO_FCR3, reg);
-                       (void)MACIO_IN32(KEYLARGO_FCR3);
-                       udelay(1);
-               }
-               if (number == 0) {
-                       if (macio->type != macio_intrepid)
-                               MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       udelay(1);
-                       MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-               } else if (number == 2) {
-                       if (macio->type != macio_intrepid)
-                               MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-                       udelay(1);
-                       MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR0);
-               } else if (number == 4) {
-                       udelay(1);
-                       MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
-                       (void)MACIO_IN32(KEYLARGO_FCR1);
-               }
-               udelay(1);
-       }
-       UNLOCK(flags);
-
-       return 0;
-}
-
-static long
-core99_firewire_enable(struct device_node* node, long param, long value)
-{
-       unsigned long flags;
-       struct macio_chip* macio;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-       if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value) {
-               UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-               (void)UN_IN(UNI_N_CLOCK_CNTL);
-       } else {
-               UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
-               (void)UN_IN(UNI_N_CLOCK_CNTL);
-       }
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long
-core99_firewire_cable_power(struct device_node* node, long param, long value)
-{
-       unsigned long flags;
-       struct macio_chip* macio;
-
-       /* Trick: we allow NULL node */
-       if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)
-               return -ENODEV;
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-       if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))
-               return -ENODEV;
-
-       LOCK(flags);
-       if (value) {
-               MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);
-               MACIO_IN8(KL_GPIO_FW_CABLE_POWER);
-               udelay(10);
-       } else {
-               MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);
-               MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);
-       }
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long
-intrepid_aack_delay_enable(struct device_node* node, long param, long value)
-{
-       unsigned long flags;
-
-       if (uninorth_rev < 0xd2)
-               return -ENODEV;
-
-       LOCK(flags);
-       if (param)
-               UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
-       else
-               UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-
-#endif /* CONFIG_POWER4 */
-
-static long
-core99_read_gpio(struct device_node* node, long param, long value)
-{
-       struct macio_chip* macio = &macio_chips[0];
-
-       return MACIO_IN8(param);
-}
-
-
-static long
-core99_write_gpio(struct device_node* node, long param, long value)
-{
-       struct macio_chip* macio = &macio_chips[0];
-
-       MACIO_OUT8(param, (u8)(value & 0xff));
-       return 0;
-}
-
-#ifdef CONFIG_POWER4
-
-static long
-g5_gmac_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip* macio = &macio_chips[0];
-       unsigned long flags;
-       u8 pbus, pid;
-
-       LOCK(flags);
-       if (value) {
-               MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
-               mb();
-               k2_skiplist[0] = NULL;
-       } else {
-               k2_skiplist[0] = node;
-               mb();
-               MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
-       }
-       
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long
-g5_fw_enable(struct device_node* node, long param, long value)
-{
-       struct macio_chip* macio = &macio_chips[0];
-       unsigned long flags;
-
-       LOCK(flags);
-       if (value) {
-               MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
-               mb();
-               k2_skiplist[1] = NULL;
-       } else {
-               k2_skiplist[1] = node;
-               mb();
-               MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
-       }
-       
-       UNLOCK(flags);
-       mdelay(1);
-
-       return 0;
-}
-
-static long
-g5_mpic_enable(struct device_node* node, long param, long value)
-{
-       unsigned long flags;
-
-       if (node->parent == NULL || strcmp(node->parent->name, "u3"))
-               return 0;
-
-       LOCK(flags);
-       UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
-       UNLOCK(flags);
-
-       return 0;
-}
-
-#ifdef CONFIG_SMP
-static long
-g5_reset_cpu(struct device_node* node, long param, long value)
-{
-       unsigned int reset_io = 0;
-       unsigned long flags;
-       struct macio_chip* macio;
-       struct device_node* np;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo2)
-               return -ENODEV;
-
-       np = find_path_device("/cpus");
-       if (np == NULL)
-               return -ENODEV;
-       for (np = np->child; np != NULL; np = np->sibling) {
-               u32* num = (u32 *)get_property(np, "reg", NULL);
-               u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
-               if (num == NULL || rst == NULL)
-                       continue;
-               if (param == *num) {
-                       reset_io = *rst;
-                       break;
-               }
-       }
-       if (np == NULL || reset_io == 0)
-               return -ENODEV;
-
-       LOCK(flags);
-       MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-       (void)MACIO_IN8(reset_io);
-       udelay(1);
-       MACIO_OUT8(reset_io, 0);
-       (void)MACIO_IN8(reset_io);
-       UNLOCK(flags);
-
-       return 0;
-}
-#endif /* CONFIG_SMP */
-
-/*
- * This can be called from pmac_smp so isn't static
- *
- * This takes the second CPU off the bus on dual CPU machines
- * running UP
- */
-void g5_phy_disable_cpu1(void)
-{
-       UN_OUT(U3_API_PHY_CONFIG_1, 0);
-}
-
-#endif /* CONFIG_POWER4 */
-
-#ifndef CONFIG_POWER4
-
-static void
-keylargo_shutdown(struct macio_chip* macio, int sleep_mode)
-{
-       u32 temp;
-
-       if (sleep_mode) {
-               mdelay(1);
-               MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
-               (void)MACIO_IN32(KEYLARGO_FCR0);
-               mdelay(1);
-       }
-
-       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-                               KL0_SCC_CELL_ENABLE |
-                               KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |
-                               KL0_IRDA_CLK19_ENABLE);
-
-       MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
-       MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
-
-       MACIO_BIC(KEYLARGO_FCR1,
-               KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
-               KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
-               KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-               KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-               KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
-               KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
-               KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
-               KL1_UIDE_ENABLE);
-
-       MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-       MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
-
-       temp = MACIO_IN32(KEYLARGO_FCR3);
-       if (macio->rev >= 2) {
-               temp |= KL3_SHUTDOWN_PLL2X;
-               if (sleep_mode)
-                       temp |= KL3_SHUTDOWN_PLL_TOTAL;
-       }
-
-       temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-               KL3_SHUTDOWN_PLLKW35;
-       if (sleep_mode)
-               temp |= KL3_SHUTDOWN_PLLKW12;
-       temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
-               | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
-       if (sleep_mode)
-               temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
-       MACIO_OUT32(KEYLARGO_FCR3, temp);
-
-       /* Flush posted writes & wait a bit */
-       (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
-}
-
-static void
-pangea_shutdown(struct macio_chip* macio, int sleep_mode)
-{
-       u32 temp;
-
-       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-                               KL0_SCC_CELL_ENABLE |
-                               KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);
-
-       MACIO_BIC(KEYLARGO_FCR1,
-               KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
-               KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
-               KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-               KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-               KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
-               KL1_UIDE_ENABLE);
-       if (pmac_mb.board_flags & PMAC_MB_MOBILE)
-               MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
-
-       MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);
-
-       temp = MACIO_IN32(KEYLARGO_FCR3);
-       temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
-               KL3_SHUTDOWN_PLLKW35;
-       temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE
-               | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);
-       if (sleep_mode)
-               temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);
-       MACIO_OUT32(KEYLARGO_FCR3, temp);
-
-       /* Flush posted writes & wait a bit */
-       (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);
-}
-
-static void
-intrepid_shutdown(struct macio_chip* macio, int sleep_mode)
-{
-       u32 temp;
-
-       MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
-                 KL0_SCC_CELL_ENABLE);
-
-       MACIO_BIC(KEYLARGO_FCR1,
-                 /*KL1_USB2_CELL_ENABLE |*/
-               KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
-               KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
-               KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE);
-       if (pmac_mb.board_flags & PMAC_MB_MOBILE)
-               MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);
-
-       temp = MACIO_IN32(KEYLARGO_FCR3);
-       temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |
-                 KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);
-       if (sleep_mode)
-               temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);
-       MACIO_OUT32(KEYLARGO_FCR3, temp);
-
-       /* Flush posted writes & wait a bit */
-       (void)MACIO_IN32(KEYLARGO_FCR0);
-       mdelay(10);
-}
-
-
-void pmac_tweak_clock_spreading(int enable)
-{
-       struct macio_chip* macio = &macio_chips[0];
-
-       /* Hack for doing clock spreading on some machines PowerBooks and
-        * iBooks. This implements the "platform-do-clockspreading" OF
-        * property as decoded manually on various models. For safety, we also
-        * check the product ID in the device-tree in cases we'll whack the i2c
-        * chip to make reasonably sure we won't set wrong values in there
-        *
-        * Of course, ultimately, we have to implement a real parser for
-        * the platform-do-* stuff...
-        */
-
-       if (macio->type == macio_intrepid) {
-               struct device_node *clock =
-                       of_find_node_by_path("/uni-n@f8000000/hw-clock");
-               if (clock && get_property(clock, "platform-do-clockspreading",
-                                         NULL)) {
-                       printk(KERN_INFO "%sabling clock spreading on Intrepid"
-                              " ASIC\n", enable ? "En" : "Dis");
-                       if (enable)
-                               UN_OUT(UNI_N_CLOCK_SPREADING, 2);
-                       else
-                               UN_OUT(UNI_N_CLOCK_SPREADING, 0);
-                       mdelay(40);
-               }
-               of_node_put(clock);
-       }
-
-       while (machine_is_compatible("PowerBook5,2") ||
-              machine_is_compatible("PowerBook5,3") ||
-              machine_is_compatible("PowerBook6,2") ||
-              machine_is_compatible("PowerBook6,3")) {
-               struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
-               struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
-               u8 buffer[9];
-               u32 *productID;
-               int i, rc, changed = 0;
-
-               if (dt == NULL)
-                       break;
-               productID = (u32 *)get_property(dt, "pid#", NULL);
-               if (productID == NULL)
-                       break;
-               while(ui2c) {
-                       struct device_node *p = of_get_parent(ui2c);
-                       if (p && !strcmp(p->name, "uni-n"))
-                               break;
-                       ui2c = of_find_node_by_type(ui2c, "i2c");
-               }
-               if (ui2c == NULL)
-                       break;
-               DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
-               rc = pmac_low_i2c_open(ui2c, 1);
-               if (rc != 0)
-                       break;
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-               DBG("read result: %d,", rc);
-               if (rc != 0) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               for (i=0; i<9; i++)
-                       DBG(" %02x", buffer[i]);
-               DBG("\n");
-
-               switch(*productID) {
-               case 0x1182:    /* AlBook 12" rev 2 */
-               case 0x1183:    /* iBook G4 12" */
-                       buffer[0] = (buffer[0] & 0x8f) | 0x70;
-                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
-                       buffer[5] = (buffer[5] & 0x80) | 0x31;
-                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
-                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xc0 : 0xba);
-                       buffer[8] = (buffer[8] & 0x00) | 0x30;
-                       changed = 1;
-                       break;
-               case 0x3142:    /* AlBook 15" (ATI M10) */
-               case 0x3143:    /* AlBook 17" (ATI M10) */
-                       buffer[0] = (buffer[0] & 0xaf) | 0x50;
-                       buffer[2] = (buffer[2] & 0x7f) | 0x00;
-                       buffer[5] = (buffer[5] & 0x80) | 0x31;
-                       buffer[6] = (buffer[6] & 0x40) | 0xb0;
-                       buffer[7] = (buffer[7] & 0x00) | (enable ? 0xd0 : 0xc0);
-                       buffer[8] = (buffer[8] & 0x00) | 0x30;
-                       changed = 1;
-                       break;
-               default:
-                       DBG("i2c-hwclock: Machine model not handled\n");
-                       break;
-               }
-               if (!changed) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               printk(KERN_INFO "%sabling clock spreading on i2c clock chip\n",
-                      enable ? "En" : "Dis");
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
-               DBG("write result: %d,", rc);
-               pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
-               rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
-               DBG("read result: %d,", rc);
-               if (rc != 0) {
-                       pmac_low_i2c_close(ui2c);
-                       break;
-               }
-               for (i=0; i<9; i++)
-                       DBG(" %02x", buffer[i]);
-               pmac_low_i2c_close(ui2c);
-               break;
-       }
-}
-
-
-static int
-core99_sleep(void)
-{
-       struct macio_chip* macio;
-       int i;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       /* We power off the wireless slot in case it was not done
-        * by the driver. We don't power it on automatically however
-        */
-       if (macio->flags & MACIO_FLAG_AIRPORT_ON)
-               core99_airport_enable(macio->of_node, 0, 0);
-
-       /* We power off the FW cable. Should be done by the driver... */
-       if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {
-               core99_firewire_enable(NULL, 0, 0);
-               core99_firewire_cable_power(NULL, 0, 0);
-       }
-
-       /* We make sure int. modem is off (in case driver lost it) */
-       if (macio->type == macio_keylargo)
-               core99_modem_enable(macio->of_node, 0, 0);
-       else
-               pangea_modem_enable(macio->of_node, 0, 0);
-
-       /* We make sure the sound is off as well */
-       core99_sound_chip_enable(macio->of_node, 0, 0);
-
-       /*
-        * Save various bits of KeyLargo
-        */
-
-       /* Save the state of the various GPIOs */
-       save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);
-       save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);
-       for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-               save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);
-       for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-               save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);
-
-       /* Save the FCRs */
-       if (macio->type == macio_keylargo)
-               save_mbcr = MACIO_IN32(KEYLARGO_MBCR);
-       save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);
-       save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);
-       save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);
-       save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);
-       save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);
-       if (macio->type == macio_pangea || macio->type == macio_intrepid)
-               save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);
-
-       /* Save state & config of DBDMA channels */
-       dbdma_save(macio, save_dbdma);
-
-       /*
-        * Turn off as much as we can
-        */
-       if (macio->type == macio_pangea)
-               pangea_shutdown(macio, 1);
-       else if (macio->type == macio_intrepid)
-               intrepid_shutdown(macio, 1);
-       else if (macio->type == macio_keylargo)
-               keylargo_shutdown(macio, 1);
-
-       /*
-        * Put the host bridge to sleep
-        */
-
-       save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);
-       /* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it
-        * enabled !
-        */
-       UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &
-              ~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));
-       udelay(100);
-       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
-       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
-       mdelay(10);
-
-       /*
-        * FIXME: A bit of black magic with OpenPIC (don't ask me why)
-        */
-       if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-               MACIO_BIS(0x506e0, 0x00400000);
-               MACIO_BIS(0x506e0, 0x80000000);
-       }
-       return 0;
-}
-
-static int
-core99_wake_up(void)
-{
-       struct macio_chip* macio;
-       int i;
-
-       macio = &macio_chips[0];
-       if (macio->type != macio_keylargo && macio->type != macio_pangea &&
-           macio->type != macio_intrepid)
-               return -ENODEV;
-
-       /*
-        * Wakeup the host bridge
-        */
-       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
-       udelay(10);
-       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
-       udelay(10);
-
-       /*
-        * Restore KeyLargo
-        */
-
-       if (macio->type == macio_keylargo) {
-               MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);
-               (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);
-       }
-       MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);
-       (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);
-       (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);
-       (void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);
-       (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);
-       MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);
-       (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);
-       if (macio->type == macio_pangea || macio->type == macio_intrepid) {
-               MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);
-               (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);
-       }
-
-       dbdma_restore(macio, save_dbdma);
-
-       MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
-       MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
-       for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
-               MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);
-       for (i=0; i<KEYLARGO_GPIO_CNT; i++)
-               MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);
-
-       /* FIXME more black magic with OpenPIC ... */
-       if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {
-               MACIO_BIC(0x506e0, 0x00400000);
-               MACIO_BIC(0x506e0, 0x80000000);
-       }
-
-       UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);
-       udelay(100);
-
-       return 0;
-}
-
-static long
-core99_sleep_state(struct device_node* node, long param, long value)
-{
-       /* Param == 1 means to enter the "fake sleep" mode that is
-        * used for CPU speed switch
-        */
-       if (param == 1) {
-               if (value == 1) {
-                       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
-                       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);
-               } else {
-                       UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
-                       udelay(10);
-                       UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
-                       udelay(10);
-               }
-               return 0;
-       }
-       if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
-               return -EPERM;
-
-       if (value == 1)
-               return core99_sleep();
-       else if (value == 0)
-               return core99_wake_up();
-       return 0;
-}
-
-#endif /* CONFIG_POWER4 */
-
-static long
-generic_dev_can_wake(struct device_node* node, long param, long value)
-{
-       /* Todo: eventually check we are really dealing with on-board
-        * video device ...
-        */
-
-       if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)
-               pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;
-       return 0;
-}
-
-static long
-generic_get_mb_info(struct device_node* node, long param, long value)
-{
-       switch(param) {
-               case PMAC_MB_INFO_MODEL:
-                       return pmac_mb.model_id;
-               case PMAC_MB_INFO_FLAGS:
-                       return pmac_mb.board_flags;
-               case PMAC_MB_INFO_NAME:
-                       /* hack hack hack... but should work */
-                       *((const char **)value) = pmac_mb.model_name;
-                       return 0;
-       }
-       return -EINVAL;
-}
-
-
-/*
- * Table definitions
- */
-
-/* Used on any machine
- */
-static struct feature_table_entry any_features[] = {
-       { PMAC_FTR_GET_MB_INFO,         generic_get_mb_info },
-       { PMAC_FTR_DEVICE_CAN_WAKE,     generic_dev_can_wake },
-       { 0, NULL }
-};
-
-#ifndef CONFIG_POWER4
-
-/* OHare based motherboards. Currently, we only use these on the
- * 2400,3400 and 3500 series powerbooks. Some older desktops seem
- * to have issues with turning on/off those asic cells
- */
-static struct feature_table_entry ohare_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
-       { PMAC_FTR_SWIM3_ENABLE,        ohare_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         ohare_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          ohare_ide_enable},
-       { PMAC_FTR_IDE_RESET,           ohare_ide_reset},
-       { PMAC_FTR_SLEEP_STATE,         ohare_sleep_state },
-       { 0, NULL }
-};
-
-/* Heathrow desktop machines (Beige G3).
- * Separated as some features couldn't be properly tested
- * and the serial port control bits appear to confuse it.
- */
-static struct feature_table_entry heathrow_desktop_features[] = {
-       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
-       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
-       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
-       { 0, NULL }
-};
-
-/* Heathrow based laptop, that is the Wallstreet and mainstreet
- * powerbooks.
- */
-static struct feature_table_entry heathrow_laptop_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        heathrow_modem_enable },
-       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
-       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
-       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   heathrow_sound_enable },
-       { PMAC_FTR_SLEEP_STATE,         heathrow_sleep_state },
-       { 0, NULL }
-};
-
-/* Paddington based machines
- * The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.
- */
-static struct feature_table_entry paddington_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          ohare_htw_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        heathrow_modem_enable },
-       { PMAC_FTR_SWIM3_ENABLE,        heathrow_floppy_enable },
-       { PMAC_FTR_MESH_ENABLE,         heathrow_mesh_enable },
-       { PMAC_FTR_IDE_ENABLE,          heathrow_ide_enable },
-       { PMAC_FTR_IDE_RESET,           heathrow_ide_reset },
-       { PMAC_FTR_BMAC_ENABLE,         heathrow_bmac_enable },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   heathrow_sound_enable },
-       { PMAC_FTR_SLEEP_STATE,         heathrow_sleep_state },
-       { 0, NULL }
-};
-
-/* Core99 & MacRISC 2 machines (all machines released since the
- * iBook (included), that is all AGP machines, except pangea
- * chipset. The pangea chipset is the "combo" UniNorth/KeyLargo
- * used on iBook2 & iMac "flow power".
- */
-static struct feature_table_entry core99_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        core99_modem_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
-       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-#ifdef CONFIG_SMP
-       { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
-#endif /* CONFIG_SMP */
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-/* RackMac
- */
-static struct feature_table_entry rackmac_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-#ifdef CONFIG_SMP
-       { PMAC_FTR_RESET_CPU,           core99_reset_cpu },
-#endif /* CONFIG_SMP */
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-/* Pangea features
- */
-static struct feature_table_entry pangea_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        pangea_modem_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
-       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-/* Intrepid features
- */
-static struct feature_table_entry intrepid_features[] = {
-       { PMAC_FTR_SCC_ENABLE,          core99_scc_enable },
-       { PMAC_FTR_MODEM_ENABLE,        pangea_modem_enable },
-       { PMAC_FTR_IDE_ENABLE,          core99_ide_enable },
-       { PMAC_FTR_IDE_RESET,           core99_ide_reset },
-       { PMAC_FTR_GMAC_ENABLE,         core99_gmac_enable },
-       { PMAC_FTR_GMAC_PHY_RESET,      core99_gmac_phy_reset },
-       { PMAC_FTR_SOUND_CHIP_ENABLE,   core99_sound_chip_enable },
-       { PMAC_FTR_AIRPORT_ENABLE,      core99_airport_enable },
-       { PMAC_FTR_USB_ENABLE,          core99_usb_enable },
-       { PMAC_FTR_1394_ENABLE,         core99_firewire_enable },
-       { PMAC_FTR_1394_CABLE_POWER,    core99_firewire_cable_power },
-       { PMAC_FTR_SLEEP_STATE,         core99_sleep_state },
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { PMAC_FTR_AACK_DELAY_ENABLE,   intrepid_aack_delay_enable },
-       { 0, NULL }
-};
-
-#else /* CONFIG_POWER4 */
-
-/* G5 features
- */
-static struct feature_table_entry g5_features[] = {
-       { PMAC_FTR_GMAC_ENABLE,         g5_gmac_enable },
-       { PMAC_FTR_1394_ENABLE,         g5_fw_enable },
-       { PMAC_FTR_ENABLE_MPIC,         g5_mpic_enable },
-#ifdef CONFIG_SMP
-       { PMAC_FTR_RESET_CPU,           g5_reset_cpu },
-#endif /* CONFIG_SMP */
-       { PMAC_FTR_READ_GPIO,           core99_read_gpio },
-       { PMAC_FTR_WRITE_GPIO,          core99_write_gpio },
-       { 0, NULL }
-};
-
-#endif /* CONFIG_POWER4 */
-
-static struct pmac_mb_def pmac_mb_defs[] = {
-#ifndef CONFIG_POWER4
-       /*
-        * Desktops
-        */
-
-       {       "AAPL,8500",                    "PowerMac 8500/8600",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,9500",                    "PowerMac 9500/9600",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,7200",                    "PowerMac 7200",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,7300",                    "PowerMac 7200/7300",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,7500",                    "PowerMac 7500",
-               PMAC_TYPE_PSURGE,               NULL,
-               0
-       },
-       {       "AAPL,ShinerESB",               "Apple Network Server",
-               PMAC_TYPE_ANS,                  NULL,
-               0
-       },
-       {       "AAPL,e407",                    "Alchemy",
-               PMAC_TYPE_ALCHEMY,              NULL,
-               0
-       },
-       {       "AAPL,e411",                    "Gazelle",
-               PMAC_TYPE_GAZELLE,              NULL,
-               0
-       },
-       {       "AAPL,Gossamer",                "PowerMac G3 (Gossamer)",
-               PMAC_TYPE_GOSSAMER,             heathrow_desktop_features,
-               0
-       },
-       {       "AAPL,PowerMac G3",             "PowerMac G3 (Silk)",
-               PMAC_TYPE_SILK,                 heathrow_desktop_features,
-               0
-       },
-       {       "PowerMac1,1",                  "Blue&White G3",
-               PMAC_TYPE_YOSEMITE,             paddington_features,
-               0
-       },
-       {       "PowerMac1,2",                  "PowerMac G4 PCI Graphics",
-               PMAC_TYPE_YIKES,                paddington_features,
-               0
-       },
-       {       "PowerMac2,1",                  "iMac FireWire",
-               PMAC_TYPE_FW_IMAC,              core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac2,2",                  "iMac FireWire",
-               PMAC_TYPE_FW_IMAC,              core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,1",                  "PowerMac G4 AGP Graphics",
-               PMAC_TYPE_SAWTOOTH,             core99_features,
-               PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,2",                  "PowerMac G4 AGP Graphics",
-               PMAC_TYPE_SAWTOOTH,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,3",                  "PowerMac G4 AGP Graphics",
-               PMAC_TYPE_SAWTOOTH,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac3,4",                  "PowerMac G4 Silver",
-               PMAC_TYPE_QUICKSILVER,          core99_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac3,5",                  "PowerMac G4 Silver",
-               PMAC_TYPE_QUICKSILVER,          core99_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac3,6",                  "PowerMac G4 Windtunnel",
-               PMAC_TYPE_WINDTUNNEL,           core99_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac4,1",                  "iMac \"Flower Power\"",
-               PMAC_TYPE_PANGEA_IMAC,          pangea_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac4,2",                  "Flat panel iMac",
-               PMAC_TYPE_FLAT_PANEL_IMAC,      pangea_features,
-               PMAC_MB_CAN_SLEEP
-       },
-       {       "PowerMac4,4",                  "eMac",
-               PMAC_TYPE_EMAC,                 core99_features,
-               PMAC_MB_MAY_SLEEP
-       },
-       {       "PowerMac5,1",                  "PowerMac G4 Cube",
-               PMAC_TYPE_CUBE,                 core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE99
-       },
-       {       "PowerMac6,1",                  "Flat panel iMac",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac6,3",                  "Flat panel iMac",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac6,4",                  "eMac",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP,
-       },
-       {       "PowerMac10,1",                 "Mac mini",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER,
-       },
-       {       "iMac,1",                       "iMac (first generation)",
-               PMAC_TYPE_ORIG_IMAC,            paddington_features,
-               0
-       },
-
-       /*
-        * Xserve's
-        */
-
-       {       "RackMac1,1",                   "XServe",
-               PMAC_TYPE_RACKMAC,              rackmac_features,
-               0,
-       },
-       {       "RackMac1,2",                   "XServe rev. 2",
-               PMAC_TYPE_RACKMAC,              rackmac_features,
-               0,
-       },
-
-       /*
-        * Laptops
-        */
-
-       {       "AAPL,3400/2400",               "PowerBook 3400",
-               PMAC_TYPE_HOOPER,               ohare_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "AAPL,3500",                    "PowerBook 3500",
-               PMAC_TYPE_KANGA,                ohare_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "AAPL,PowerBook1998",           "PowerBook Wallstreet",
-               PMAC_TYPE_WALLSTREET,           heathrow_laptop_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "PowerBook1,1",                 "PowerBook 101 (Lombard)",
-               PMAC_TYPE_101_PBOOK,            paddington_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE
-       },
-       {       "PowerBook2,1",                 "iBook (first generation)",
-               PMAC_TYPE_ORIG_IBOOK,           core99_features,
-               PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
-       },
-       {       "PowerBook2,2",                 "iBook FireWire",
-               PMAC_TYPE_FW_IBOOK,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
-               PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,1",                 "PowerBook Pismo",
-               PMAC_TYPE_PISMO,                core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |
-               PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,2",                 "PowerBook Titanium",
-               PMAC_TYPE_TITANIUM,             core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,3",                 "PowerBook Titanium II",
-               PMAC_TYPE_TITANIUM2,            core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,4",                 "PowerBook Titanium III",
-               PMAC_TYPE_TITANIUM3,            core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook3,5",                 "PowerBook Titanium IV",
-               PMAC_TYPE_TITANIUM4,            core99_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook4,1",                 "iBook 2",
-               PMAC_TYPE_IBOOK2,               pangea_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook4,2",                 "iBook 2",
-               PMAC_TYPE_IBOOK2,               pangea_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook4,3",                 "iBook 2 rev. 2",
-               PMAC_TYPE_IBOOK2,               pangea_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE
-       },
-       {       "PowerBook5,1",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,2",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,3",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,4",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,5",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,6",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,7",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,8",                 "PowerBook G4 15\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook5,9",                 "PowerBook G4 17\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,1",                 "PowerBook G4 12\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,2",                 "PowerBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,3",                 "iBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,4",                 "PowerBook G4 12\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,5",                 "iBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,7",                 "iBook G4",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-       {       "PowerBook6,8",                 "PowerBook G4 12\"",
-               PMAC_TYPE_UNKNOWN_INTREPID,     intrepid_features,
-               PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
-       },
-#else /* CONFIG_POWER4 */
-       {       "PowerMac7,2",                  "PowerMac G5",
-               PMAC_TYPE_POWERMAC_G5,          g5_features,
-               0,
-       },
-#endif /* CONFIG_POWER4 */
-};
-
-/*
- * The toplevel feature_call callback
- */
-long
-pmac_do_feature_call(unsigned int selector, ...)
-{
-       struct device_node* node;
-       long param, value;
-       int i;
-       feature_call func = NULL;
-       va_list args;
-
-       if (pmac_mb.features)
-               for (i=0; pmac_mb.features[i].function; i++)
-                       if (pmac_mb.features[i].selector == selector) {
-                               func = pmac_mb.features[i].function;
-                               break;
-                       }
-       if (!func)
-               for (i=0; any_features[i].function; i++)
-                       if (any_features[i].selector == selector) {
-                               func = any_features[i].function;
-                               break;
-                       }
-       if (!func)
-               return -ENODEV;
-
-       va_start(args, selector);
-       node = (struct device_node*)va_arg(args, void*);
-       param = va_arg(args, long);
-       value = va_arg(args, long);
-       va_end(args);
-
-       return func(node, param, value);
-}
-
-static int __init
-probe_motherboard(void)
-{
-       int i;
-       struct macio_chip* macio = &macio_chips[0];
-       const char* model = NULL;
-       struct device_node *dt;
-
-       /* 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");
-       if (dt != NULL)
-               model = (const char *) 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];
-               goto found;
-           }
-       }
-       for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
-           if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
-               pmac_mb = pmac_mb_defs[i];
-               goto found;
-           }
-       }
-
-       /* Fallback to selection depending on mac-io chip type */
-       switch(macio->type) {
-#ifndef CONFIG_POWER4
-           case macio_grand_central:
-               pmac_mb.model_id = PMAC_TYPE_PSURGE;
-               pmac_mb.model_name = "Unknown PowerSurge";
-               break;
-           case macio_ohare:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;
-               pmac_mb.model_name = "Unknown OHare-based";
-               break;
-           case macio_heathrow:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;
-               pmac_mb.model_name = "Unknown Heathrow-based";
-               pmac_mb.features = heathrow_desktop_features;
-               break;
-           case macio_paddington:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;
-               pmac_mb.model_name = "Unknown Paddington-based";
-               pmac_mb.features = paddington_features;
-               break;
-           case macio_keylargo:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;
-               pmac_mb.model_name = "Unknown Keylargo-based";
-               pmac_mb.features = core99_features;
-               break;
-           case macio_pangea:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;
-               pmac_mb.model_name = "Unknown Pangea-based";
-               pmac_mb.features = pangea_features;
-               break;
-           case macio_intrepid:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;
-               pmac_mb.model_name = "Unknown Intrepid-based";
-               pmac_mb.features = intrepid_features;
-               break;
-#else /* CONFIG_POWER4 */
-           case macio_keylargo2:
-               pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
-               pmac_mb.model_name = "Unknown G5";
-               pmac_mb.features = g5_features;
-               break;
-#endif /* CONFIG_POWER4 */
-           default:
-               return -ENODEV;
-       }
-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;
-               /* 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.
-                */
-               if (__raw_readl(mach_id_ptr) & 0x20000000UL)
-                       pmac_mb.model_id = PMAC_TYPE_COMET;
-               iounmap(mach_id_ptr);
-       }
-#endif /* CONFIG_POWER4 */
-
-#ifdef CONFIG_6xx
-       /* Set default value of powersave_nap on machines that support it.
-        * It appears that uninorth rev 3 has a problem with it, we don't
-        * enable it on those. In theory, the flush-on-lock property is
-        * supposed to be set when not supported, but I'm not very confident
-        * 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) {
-                       printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
-                       break;
-               }
-               np = np->child;
-               /* Nap mode not supported on SMP */
-               if (np->sibling)
-                       break;
-               /* Nap mode not supported if flush-on-lock property is present */
-               if (get_property(np, "flush-on-lock", NULL))
-                       break;
-               powersave_nap = 1;
-               printk(KERN_INFO "Processor NAP mode on idle enabled.\n");
-               break;
-       }
-
-       /* On CPUs that support it (750FX), lowspeed by default during
-        * NAP mode
-        */
-       powersave_lowspeed = 1;
-#endif /* CONFIG_6xx */
-#ifdef CONFIG_POWER4
-       powersave_nap = 1;
-#endif
-       /* Check for "mobile" machine */
-       if (model && (strncmp(model, "PowerBook", 9) == 0
-                  || strncmp(model, "iBook", 5) == 0))
-               pmac_mb.board_flags |= PMAC_MB_MOBILE;
-
-
-       printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
-       return 0;
-}
-
-/* Initialize the Core99 UniNorth host bridge and memory controller
- */
-static void __init
-probe_uninorth(void)
-{
-       unsigned long actrl;
-
-       /* Locate core99 Uni-N */
-       uninorth_node = of_find_node_by_name(NULL, "uni-n");
-       /* Locate G5 u3 */
-       if (uninorth_node == NULL) {
-               uninorth_node = of_find_node_by_name(NULL, "u3");
-               uninorth_u3 = 1;
-       }
-       if (uninorth_node && uninorth_node->n_addrs > 0) {
-               unsigned long address = uninorth_node->addrs[0].address;
-               uninorth_base = ioremap(address, 0x40000);
-               uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
-               if (uninorth_u3)
-                       u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
-       } else
-               uninorth_node = NULL;
-
-       if (!uninorth_node)
-               return;
-
-       printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
-              uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
-       printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
-
-       /* Set the arbitrer QAck delay according to what Apple does
-        */
-       if (uninorth_rev < 0x11) {
-               actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
-               actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :
-                       UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
-               UN_OUT(UNI_N_ARB_CTRL, actrl);
-       }
-
-       /* Some more magic as done by them in recent MacOS X on UniNorth
-        * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI
-        * memory timeout
-        */
-       if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0)
-               UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);
-}
-
-static void __init
-probe_one_macio(const char* name, const char* compat, int type)
-{
-       struct device_node*     node;
-       int                     i;
-       volatile u32 __iomem *  base;
-       u32*                    revp;
-
-       node = find_devices(name);
-       if (!node || !node->n_addrs)
-               return;
-       if (compat)
-               do {
-                       if (device_is_compatible(node, compat))
-                               break;
-                       node = node->next;
-               } while (node);
-       if (!node)
-               return;
-       for(i=0; i<MAX_MACIO_CHIPS; i++) {
-               if (!macio_chips[i].of_node)
-                       break;
-               if (macio_chips[i].of_node == node)
-                       return;
-       }
-       if (i >= MAX_MACIO_CHIPS) {
-               printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
-               printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
-               return;
-       }
-       base = ioremap(node->addrs[0].address, node->addrs[0].size);
-       if (!base) {
-               printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
-               return;
-       }
-       if (type == macio_keylargo) {
-               u32* did = (u32 *)get_property(node, "device-id", NULL);
-               if (*did == 0x00000025)
-                       type = macio_pangea;
-               if (*did == 0x0000003e)
-                       type = macio_intrepid;
-       }
-       macio_chips[i].of_node  = node;
-       macio_chips[i].type     = type;
-       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 = (u32 *)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",
-               macio_names[type], macio_chips[i].rev, macio_chips[i].base);
-}
-
-static int __init
-probe_macios(void)
-{
-       /* Warning, ordering is important */
-       probe_one_macio("gc", NULL, macio_grand_central);
-       probe_one_macio("ohare", NULL, macio_ohare);
-       probe_one_macio("pci106b,7", NULL, macio_ohareII);
-       probe_one_macio("mac-io", "keylargo", macio_keylargo);
-       probe_one_macio("mac-io", "paddington", macio_paddington);
-       probe_one_macio("mac-io", "gatwick", macio_gatwick);
-       probe_one_macio("mac-io", "heathrow", macio_heathrow);
-       probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
-
-       /* Make sure the "main" macio chip appear first */
-       if (macio_chips[0].type == macio_gatwick
-           && macio_chips[1].type == macio_heathrow) {
-               struct macio_chip temp = macio_chips[0];
-               macio_chips[0] = macio_chips[1];
-               macio_chips[1] = temp;
-       }
-       if (macio_chips[0].type == macio_ohareII
-           && macio_chips[1].type == macio_ohare) {
-               struct macio_chip temp = macio_chips[0];
-               macio_chips[0] = macio_chips[1];
-               macio_chips[1] = temp;
-       }
-       macio_chips[0].lbus.index = 0;
-       macio_chips[1].lbus.index = 1;
-
-       return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
-}
-
-static void __init
-initial_serial_shutdown(struct device_node* np)
-{
-       int len;
-       struct slot_names_prop {
-               int     count;
-               char    name[1];
-       } *slots;
-       char *conn;
-       int port_type = PMAC_SCC_ASYNC;
-       int modem = 0;
-
-       slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
-       conn = get_property(np, "AAPL,connector", &len);
-       if (conn && (strcmp(conn, "infrared") == 0))
-               port_type = PMAC_SCC_IRDA;
-       else if (device_is_compatible(np, "cobalt"))
-               modem = 1;
-       else if (slots && slots->count > 0) {
-               if (strcmp(slots->name, "IrDA") == 0)
-                       port_type = PMAC_SCC_IRDA;
-               else if (strcmp(slots->name, "Modem") == 0)
-                       modem = 1;
-       }
-       if (modem)
-               pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);
-       pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);
-}
-
-static void __init
-set_initial_features(void)
-{
-       struct device_node* np;
-
-       /* That hack appears to be necessary for some StarMax motherboards
-        * but I'm not too sure it was audited for side-effects on other
-        * ohare based machines...
-        * Since I still have difficulties figuring the right way to
-        * 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")) {
-               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);
-       } else if (macio_chips[1].type == macio_ohare) {
-               struct macio_chip* macio = &macio_chips[1];
-               MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
-       }
-
-#ifdef CONFIG_POWER4
-       if (macio_chips[0].type == macio_keylargo2) {
-#ifndef CONFIG_SMP
-               /* On SMP machines running UP, we have the second CPU eating
-                * bus cycles. We need to take it off the bus. This is done
-                * from pmac_smp for SMP kernels running on one CPU
-                */
-               np = of_find_node_by_type(NULL, "cpu");
-               if (np != NULL)
-                       np = of_find_node_by_type(np, "cpu");
-               if (np != NULL) {
-                       g5_phy_disable_cpu1();
-                       of_node_put(np);
-               }
-#endif /* CONFIG_SMP */
-               /* Enable GMAC for now for PCI probing. It will be disabled
-                * later on after PCI probe
-                */
-               np = of_find_node_by_name(NULL, "ethernet");
-               while(np) {
-                       if (device_is_compatible(np, "K2-GMAC"))
-                               g5_gmac_enable(np, 0, 1);
-                       np = of_find_node_by_name(np, "ethernet");
-               }
-
-               /* Enable FW before PCI probe. Will be disabled later on
-                * Note: We should have a batter way to check that we are
-                * dealing with uninorth internal cell and not a PCI cell
-                * on the external PCI. The code below works though.
-                */
-               np = of_find_node_by_name(NULL, "firewire");
-               while(np) {
-                       if (device_is_compatible(np, "pci106b,5811")) {
-                               macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
-                               g5_fw_enable(np, 0, 1);
-                       }
-                       np = of_find_node_by_name(np, "firewire");
-               }
-       }
-#else /* CONFIG_POWER4 */
-
-       if (macio_chips[0].type == macio_keylargo ||
-           macio_chips[0].type == macio_pangea ||
-           macio_chips[0].type == macio_intrepid) {
-               /* Enable GMAC for now for PCI probing. It will be disabled
-                * later on after PCI probe
-                */
-               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"))
-                               core99_gmac_enable(np, 0, 1);
-                       np = of_find_node_by_name(np, "ethernet");
-               }
-
-               /* Enable FW before PCI probe. Will be disabled later on
-                * Note: We should have a batter way to check that we are
-                * dealing with uninorth internal cell and not a PCI cell
-                * on the external PCI. The code below works though.
-                */
-               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"))) {
-                               macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
-                               core99_firewire_enable(np, 0, 1);
-                       }
-                       np = of_find_node_by_name(np, "firewire");
-               }
-
-               /* Enable ATA-100 before PCI probe. */
-               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")) {
-                               core99_ata100_enable(np, 1);
-                       }
-                       np = of_find_node_by_name(np, "ata-6");
-               }
-
-               /* Switch airport off */
-               np = find_devices("radio");
-               while(np) {
-                       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;
-               }
-       }
-
-       /* On all machines that support sound PM, switch sound off */
-       if (macio_chips[0].of_node)
-               pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,
-                       macio_chips[0].of_node, 0, 0);
-
-       /* While on some desktop G3s, we turn it back on */
-       if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow
-               && (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||
-                   pmac_mb.model_id == PMAC_TYPE_SILK)) {
-               struct macio_chip* macio = &macio_chips[0];
-               MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);
-               MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
-       }
-
-       /* Some machine models need the clock chip to be properly setup for
-        * clock spreading now. This should be a platform function but we
-        * don't do these at the moment
-        */
-       pmac_tweak_clock_spreading(1);
-
-#endif /* CONFIG_POWER4 */
-
-       /* On all machines, switch modem & serial ports off */
-       np = find_devices("ch-a");
-       while(np) {
-               initial_serial_shutdown(np);
-               np = np->next;
-       }
-       np = find_devices("ch-b");
-       while(np) {
-               initial_serial_shutdown(np);
-               np = np->next;
-       }
-}
-
-void __init
-pmac_feature_init(void)
-{
-       /* Detect the UniNorth memory controller */
-       probe_uninorth();
-
-       /* Probe mac-io controllers */
-       if (probe_macios()) {
-               printk(KERN_WARNING "No mac-io chip found\n");
-               return;
-       }
-
-       /* Setup low-level i2c stuffs */
-       pmac_init_low_i2c();
-
-       /* Probe machine type */
-       if (probe_motherboard())
-               printk(KERN_WARNING "Unknown PowerMac !\n");
-
-       /* Set some initial features (turn off some chips that will
-        * be later turned on)
-        */
-       set_initial_features();
-}
-
-int __init
-pmac_feature_late_init(void)
-{
-       struct device_node* np;
-
-       /* Request some resources late */
-       if (uninorth_node)
-               request_OF_resource(uninorth_node, 0, NULL);
-       np = find_devices("hammerhead");
-       if (np)
-               request_OF_resource(np, 0, NULL);
-       np = find_devices("interrupt-controller");
-       if (np)
-               request_OF_resource(np, 0, NULL);
-       return 0;
-}
-
-device_initcall(pmac_feature_late_init);
-
-#ifdef CONFIG_POWER4
-
-static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
-{
-       int     freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
-       int     bits[8] = { 8,16,0,32,2,4,0,0 };
-       int     freq = (frq >> 8) & 0xf;
-
-       if (freqs[freq] == 0)
-               printk("%s: Unknown HT link frequency %x\n", name, freq);
-       else
-               printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
-                      name, freqs[freq],
-                      bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
-}
-
-void __init pmac_check_ht_link(void)
-{
-       u32     ufreq, freq, ucfg, cfg;
-       struct device_node *pcix_node;
-       u8      px_bus, px_devfn;
-       struct pci_controller *px_hose;
-
-       (void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
-       ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
-       ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
-       dump_HT_speeds("U3 HyperTransport", cfg, freq);
-
-       pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
-       if (pcix_node == NULL) {
-               printk("No PCI-X bridge found\n");
-               return;
-       }
-       if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
-               printk("PCI-X bridge found but not matched to pci\n");
-               return;
-       }
-       px_hose = pci_find_hose_for_OF_device(pcix_node);
-       if (px_hose == NULL) {
-               printk("PCI-X bridge found but not matched to host\n");
-               return;
-       }       
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
-       dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
-       early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
-       dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
-}
-
-#endif /* CONFIG_POWER4 */
-
-/*
- * Early video resume hook
- */
-
-static void (*pmac_early_vresume_proc)(void *data);
-static void *pmac_early_vresume_data;
-
-void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
-{
-       if (_machine != _MACH_Pmac)
-               return;
-       preempt_disable();
-       pmac_early_vresume_proc = proc;
-       pmac_early_vresume_data = data;
-       preempt_enable();
-}
-EXPORT_SYMBOL(pmac_set_early_video_resume);
-
-void pmac_call_early_video_resume(void)
-{
-       if (pmac_early_vresume_proc)
-               pmac_early_vresume_proc(pmac_early_vresume_data);
-}
-
-/*
- * AGP related suspend/resume code
- */
-
-static struct pci_dev *pmac_agp_bridge;
-static int (*pmac_agp_suspend)(struct pci_dev *bridge);
-static int (*pmac_agp_resume)(struct pci_dev *bridge);
-
-void pmac_register_agp_pm(struct pci_dev *bridge,
-                                int (*suspend)(struct pci_dev *bridge),
-                                int (*resume)(struct pci_dev *bridge))
-{
-       if (suspend || resume) {
-               pmac_agp_bridge = bridge;
-               pmac_agp_suspend = suspend;
-               pmac_agp_resume = resume;
-               return;
-       }
-       if (bridge != pmac_agp_bridge)
-               return;
-       pmac_agp_suspend = pmac_agp_resume = NULL;
-       return;
-}
-EXPORT_SYMBOL(pmac_register_agp_pm);
-
-void pmac_suspend_agp_for_card(struct pci_dev *dev)
-{
-       if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)
-               return;
-       if (pmac_agp_bridge->bus != dev->bus)
-               return;
-       pmac_agp_suspend(pmac_agp_bridge);
-}
-EXPORT_SYMBOL(pmac_suspend_agp_for_card);
-
-void pmac_resume_agp_for_card(struct pci_dev *dev)
-{
-       if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)
-               return;
-       if (pmac_agp_bridge->bus != dev->bus)
-               return;
-       pmac_agp_resume(pmac_agp_bridge);
-}
-EXPORT_SYMBOL(pmac_resume_agp_for_card);
diff --git a/arch/ppc/platforms/pmac_low_i2c.c b/arch/ppc/platforms/pmac_low_i2c.c
deleted file mode 100644 (file)
index 08583fc..0000000
+++ /dev/null
@@ -1,511 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_low_i2c.c
- *
- *  Copyright (C) 2003 Ben. 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 Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- *  This file contains some low-level i2c access routines that
- *  need to be used by various bits of the PowerMac platform code
- *  at times where the real asynchronous & interrupt driven driver
- *  cannot be used. The API borrows some semantics from the darwin
- *  driver in order to ease the implementation of the platform
- *  properties parser
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <asm/keylargo.h>
-#include <asm/uninorth.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/pmac_low_i2c.h>
-
-#define MAX_LOW_I2C_HOST       4
-
-#if 1
-#define DBG(x...) do {\
-               printk(KERN_DEBUG "KW:" x);     \
-       } while(0)
-#else
-#define DBGG(x...)
-#endif
-
-struct low_i2c_host;
-
-typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
-
-struct low_i2c_host
-{
-       struct device_node      *np;            /* OF device node */
-       struct semaphore        mutex;          /* Access mutex for use by i2c-keywest */
-       low_i2c_func_t          func;           /* Access function */
-       int                     is_open : 1;    /* Poor man's access control */
-       int                     mode;           /* Current mode */
-       int                     channel;        /* Current channel */
-       int                     num_channels;   /* Number of channels */
-       void __iomem *          base;           /* For keywest-i2c, base address */
-       int                     bsteps;         /* And register stepping */
-       int                     speed;          /* And speed */
-};
-
-static struct low_i2c_host     low_i2c_hosts[MAX_LOW_I2C_HOST];
-
-/* No locking is necessary on allocation, we are running way before
- * anything can race with us
- */
-static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
-{
-       int i;
-
-       for (i = 0; i < MAX_LOW_I2C_HOST; i++)
-               if (low_i2c_hosts[i].np == np)
-                       return &low_i2c_hosts[i];
-       return NULL;
-}
-
-/*
- *
- * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
- *
- */
-
-/*
- * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
- * should be moved somewhere in include/asm-ppc/
- */
-/* Register indices */
-typedef enum {
-       reg_mode = 0,
-       reg_control,
-       reg_status,
-       reg_isr,
-       reg_ier,
-       reg_addr,
-       reg_subaddr,
-       reg_data
-} reg_t;
-
-
-/* Mode register */
-#define KW_I2C_MODE_100KHZ     0x00
-#define KW_I2C_MODE_50KHZ      0x01
-#define KW_I2C_MODE_25KHZ      0x02
-#define KW_I2C_MODE_DUMB       0x00
-#define KW_I2C_MODE_STANDARD   0x04
-#define KW_I2C_MODE_STANDARDSUB        0x08
-#define KW_I2C_MODE_COMBINED   0x0C
-#define KW_I2C_MODE_MODE_MASK  0x0C
-#define KW_I2C_MODE_CHAN_MASK  0xF0
-
-/* Control register */
-#define KW_I2C_CTL_AAK         0x01
-#define KW_I2C_CTL_XADDR       0x02
-#define KW_I2C_CTL_STOP                0x04
-#define KW_I2C_CTL_START       0x08
-
-/* Status register */
-#define KW_I2C_STAT_BUSY       0x01
-#define KW_I2C_STAT_LAST_AAK   0x02
-#define KW_I2C_STAT_LAST_RW    0x04
-#define KW_I2C_STAT_SDA                0x08
-#define KW_I2C_STAT_SCL                0x10
-
-/* IER & ISR registers */
-#define KW_I2C_IRQ_DATA                0x01
-#define KW_I2C_IRQ_ADDR                0x02
-#define KW_I2C_IRQ_STOP                0x04
-#define KW_I2C_IRQ_START       0x08
-#define KW_I2C_IRQ_MASK                0x0F
-
-/* State machine states */
-enum {
-       state_idle,
-       state_addr,
-       state_read,
-       state_write,
-       state_stop,
-       state_dead
-};
-
-#define WRONG_STATE(name) do {\
-               printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
-                      name, __kw_state_names[state], isr); \
-       } while(0)
-
-static const char *__kw_state_names[] = {
-       "state_idle",
-       "state_addr",
-       "state_read",
-       "state_write",
-       "state_stop",
-       "state_dead"
-};
-
-static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
-{
-       return in_8(host->base + (((unsigned)reg) << host->bsteps));
-}
-
-static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
-{
-       out_8(host->base + (((unsigned)reg) << host->bsteps), val);
-       (void)__kw_read_reg(host, reg_subaddr);
-}
-
-#define kw_write_reg(reg, val) __kw_write_reg(host, reg, val) 
-#define kw_read_reg(reg)       __kw_read_reg(host, reg) 
-
-
-/* Don't schedule, the g5 fan controller is too
- * timing sensitive
- */
-static u8 kw_wait_interrupt(struct low_i2c_host* host)
-{
-       int i;
-       u8 isr;
-       
-       for (i = 0; i < 200000; i++) {
-               isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
-               if (isr != 0)
-                       return isr;
-               udelay(1);
-       }
-       return isr;
-}
-
-static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
-{
-       u8 ack;
-
-       if (isr == 0) {
-               if (state != state_stop) {
-                       DBG("KW: Timeout !\n");
-                       *rc = -EIO;
-                       goto stop;
-               }
-               if (state == state_stop) {
-                       ack = kw_read_reg(reg_status);
-                       if (!(ack & KW_I2C_STAT_BUSY)) {
-                               state = state_idle;
-                               kw_write_reg(reg_ier, 0x00);
-                       }
-               }
-               return state;
-       }
-
-       if (isr & KW_I2C_IRQ_ADDR) {
-               ack = kw_read_reg(reg_status);
-               if (state != state_addr) {
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-                       WRONG_STATE("KW_I2C_IRQ_ADDR"); 
-                       *rc = -EIO;
-                       goto stop;
-               }
-               if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {                        
-                       *rc = -ENODEV;
-                       DBG("KW: NAK on address\n");
-                       return state_stop;                   
-               } else {
-                       if (rw) {
-                               state = state_read;
-                               if (*len > 1)
-                                       kw_write_reg(reg_control, KW_I2C_CTL_AAK);
-                       } else {
-                               state = state_write;
-                               kw_write_reg(reg_data, **data);
-                               (*data)++; (*len)--;
-                       }
-               }
-               kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
-       }
-
-       if (isr & KW_I2C_IRQ_DATA) {
-               if (state == state_read) {
-                       **data = kw_read_reg(reg_data);
-                       (*data)++; (*len)--;
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       if ((*len) == 0)
-                               state = state_stop;
-                       else if ((*len) == 1)
-                               kw_write_reg(reg_control, 0);
-               } else if (state == state_write) {
-                       ack = kw_read_reg(reg_status);
-                       if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-                               DBG("KW: nack on data write\n");
-                               *rc = -EIO;
-                               goto stop;
-                       } else if (*len) {
-                               kw_write_reg(reg_data, **data);
-                               (*data)++; (*len)--;
-                       } else {
-                               kw_write_reg(reg_control, KW_I2C_CTL_STOP);
-                               state = state_stop;
-                               *rc = 0;
-                       }
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-               } else {
-                       kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
-                       WRONG_STATE("KW_I2C_IRQ_DATA"); 
-                       if (state != state_stop) {
-                               *rc = -EIO;
-                               goto stop;
-                       }
-               }
-       }
-
-       if (isr & KW_I2C_IRQ_STOP) {
-               kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
-               if (state != state_stop) {
-                       WRONG_STATE("KW_I2C_IRQ_STOP");
-                       *rc = -EIO;
-               }
-               return state_idle;
-       }
-
-       if (isr & KW_I2C_IRQ_START)
-               kw_write_reg(reg_isr, KW_I2C_IRQ_START);
-
-       return state;
-
- stop:
-       kw_write_reg(reg_control, KW_I2C_CTL_STOP);     
-       return state_stop;
-}
-
-static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
-{
-       u8 mode_reg = host->speed;
-       int state = state_addr;
-       int rc = 0;
-
-       /* Setup mode & subaddress if any */
-       switch(host->mode) {
-       case pmac_low_i2c_mode_dumb:
-               printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
-               return -EINVAL;
-       case pmac_low_i2c_mode_std:
-               mode_reg |= KW_I2C_MODE_STANDARD;
-               break;
-       case pmac_low_i2c_mode_stdsub:
-               mode_reg |= KW_I2C_MODE_STANDARDSUB;
-               kw_write_reg(reg_subaddr, subaddr);
-               break;
-       case pmac_low_i2c_mode_combined:
-               mode_reg |= KW_I2C_MODE_COMBINED;
-               kw_write_reg(reg_subaddr, subaddr);
-               break;
-       }
-
-       /* Setup channel & clear pending irqs */
-       kw_write_reg(reg_isr, kw_read_reg(reg_isr));
-       kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
-       kw_write_reg(reg_status, 0);
-
-       /* Set up address and r/w bit */
-       kw_write_reg(reg_addr, addr);
-
-       /* Start sending address & disable interrupt*/
-       kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
-       kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
-
-       /* State machine, to turn into an interrupt handler */
-       while(state != state_idle) {
-               u8 isr = kw_wait_interrupt(host);
-               state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
-       }
-
-       return rc;
-}
-
-static void keywest_low_i2c_add(struct device_node *np)
-{
-       struct low_i2c_host     *host = find_low_i2c_host(NULL);
-       unsigned long           *psteps, *prate, steps, aoffset = 0;
-       struct device_node      *parent;
-
-       if (host == NULL) {
-               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
-                      np->full_name);
-               return;
-       }
-       memset(host, 0, sizeof(*host));
-
-       init_MUTEX(&host->mutex);
-       host->np = of_node_get(np);     
-       psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
-       steps = psteps ? (*psteps) : 0x10;
-       for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
-               steps >>= 1;
-       parent = of_get_parent(np);
-       host->num_channels = 1;
-       if (parent && parent->name[0] == 'u') {
-               host->num_channels = 2;
-               aoffset = 3;
-       }
-       /* Select interface rate */
-       host->speed = KW_I2C_MODE_100KHZ;
-       prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
-       if (prate) switch(*prate) {
-       case 100:
-               host->speed = KW_I2C_MODE_100KHZ;
-               break;
-       case 50:
-               host->speed = KW_I2C_MODE_50KHZ;
-               break;
-       case 25:
-               host->speed = KW_I2C_MODE_25KHZ;
-               break;
-       }       
-       host->mode = pmac_low_i2c_mode_std;
-       host->base = ioremap(np->addrs[0].address + aoffset,
-                                               np->addrs[0].size);
-       host->func = keywest_low_i2c_func;
-}
-
-/*
- *
- * PMU implementation
- *
- */
-
-
-#ifdef CONFIG_ADB_PMU
-
-static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
-{
-       // TODO
-       return -ENODEV;
-}
-
-static void pmu_low_i2c_add(struct device_node *np)
-{
-       struct low_i2c_host     *host = find_low_i2c_host(NULL);
-
-       if (host == NULL) {
-               printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
-                      np->full_name);
-               return;
-       }
-       memset(host, 0, sizeof(*host));
-
-       init_MUTEX(&host->mutex);
-       host->np = of_node_get(np);     
-       host->num_channels = 3;
-       host->mode = pmac_low_i2c_mode_std;
-       host->func = pmu_low_i2c_func;
-}
-
-#endif /* CONFIG_ADB_PMU */
-
-void __init pmac_init_low_i2c(void)
-{
-       struct device_node *np;
-
-       /* Probe keywest-i2c busses */
-       np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
-       while(np) {
-               keywest_low_i2c_add(np);
-               np = of_find_compatible_node(np, "i2c", "keywest-i2c");
-       }
-
-#ifdef CONFIG_ADB_PMU
-       /* Probe PMU busses */
-       np = of_find_node_by_name(NULL, "via-pmu");
-       if (np)
-               pmu_low_i2c_add(np);
-#endif /* CONFIG_ADB_PMU */
-
-       /* TODO: Add CUDA support as well */
-}
-
-int pmac_low_i2c_lock(struct device_node *np)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       down(&host->mutex);
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_lock);
-
-int pmac_low_i2c_unlock(struct device_node *np)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       up(&host->mutex);
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_unlock);
-
-
-int pmac_low_i2c_open(struct device_node *np, int channel)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-
-       if (channel >= host->num_channels)
-               return -EINVAL;
-
-       down(&host->mutex);
-       host->is_open = 1;
-       host->channel = channel;
-
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_open);
-
-int pmac_low_i2c_close(struct device_node *np)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-
-       host->is_open = 0;
-       up(&host->mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_close);
-
-int pmac_low_i2c_setmode(struct device_node *np, int mode)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       WARN_ON(!host->is_open);
-       host->mode = mode;
-
-       return 0;
-}
-EXPORT_SYMBOL(pmac_low_i2c_setmode);
-
-int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
-{
-       struct low_i2c_host *host = find_low_i2c_host(np);
-
-       if (!host)
-               return -ENODEV;
-       WARN_ON(!host->is_open);
-
-       return host->func(host, addrdir, subaddr, data, len);
-}
-EXPORT_SYMBOL(pmac_low_i2c_xfer);
-
diff --git a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c
deleted file mode 100644 (file)
index 8c9b008..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- *  arch/ppc/platforms/pmac_nvram.c
- *
- *  Copyright (C) 2002 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 Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- *  Todo: - add support for the OF persistent properties
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/nvram.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#include <linux/bootmem.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/nvram.h>
-
-#define DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#define NVRAM_SIZE             0x2000  /* 8kB of non-volatile RAM */
-
-#define CORE99_SIGNATURE       0x5a
-#define CORE99_ADLER_START     0x14
-
-/* On Core99, nvram is either a sharp, a micron or an AMD flash */
-#define SM_FLASH_STATUS_DONE   0x80
-#define SM_FLASH_STATUS_ERR            0x38
-#define SM_FLASH_CMD_ERASE_CONFIRM     0xd0
-#define SM_FLASH_CMD_ERASE_SETUP       0x20
-#define SM_FLASH_CMD_RESET             0xff
-#define SM_FLASH_CMD_WRITE_SETUP       0x40
-#define SM_FLASH_CMD_CLEAR_STATUS      0x50
-#define SM_FLASH_CMD_READ_STATUS       0x70
-
-/* CHRP NVRAM header */
-struct chrp_header {
-  u8           signature;
-  u8           cksum;
-  u16          len;
-  char          name[12];
-  u8           data[0];
-};
-
-struct core99_header {
-  struct chrp_header   hdr;
-  u32                  adler;
-  u32                  generation;
-  u32                  reserved[2];
-};
-
-/*
- * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
- */
-static int nvram_naddrs;
-static volatile unsigned char *nvram_addr;
-static volatile unsigned char *nvram_data;
-static int nvram_mult, is_core_99;
-static int core99_bank = 0;
-static int nvram_partitions[3];
-static DEFINE_SPINLOCK(nv_lock);
-
-extern int pmac_newworld;
-extern int system_running;
-
-static int (*core99_write_bank)(int bank, u8* datas);
-static int (*core99_erase_bank)(int bank);
-
-static char *nvram_image;
-
-
-static unsigned char core99_nvram_read_byte(int addr)
-{
-       if (nvram_image == NULL)
-               return 0xff;
-       return nvram_image[addr];
-}
-
-static void core99_nvram_write_byte(int addr, unsigned char val)
-{
-       if (nvram_image == NULL)
-               return;
-       nvram_image[addr] = val;
-}
-
-
-static unsigned char direct_nvram_read_byte(int addr)
-{
-       return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
-}
-
-static void direct_nvram_write_byte(int addr, unsigned char val)
-{
-       out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val);
-}
-
-
-static unsigned char indirect_nvram_read_byte(int addr)
-{
-       unsigned char val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&nv_lock, flags);
-       out_8(nvram_addr, addr >> 5);
-       val = in_8(&nvram_data[(addr & 0x1f) << 4]);
-       spin_unlock_irqrestore(&nv_lock, flags);
-
-       return val;
-}
-
-static void indirect_nvram_write_byte(int addr, unsigned char val)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&nv_lock, flags);
-       out_8(nvram_addr, addr >> 5);
-       out_8(&nvram_data[(addr & 0x1f) << 4], val);
-       spin_unlock_irqrestore(&nv_lock, flags);
-}
-
-
-#ifdef CONFIG_ADB_PMU
-
-static void pmu_nvram_complete(struct adb_request *req)
-{
-       if (req->arg)
-               complete((struct completion *)req->arg);
-}
-
-static unsigned char pmu_nvram_read_byte(int addr)
-{
-       struct adb_request req;
-       DECLARE_COMPLETION(req_complete); 
-       
-       req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
-       if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
-                       (addr >> 8) & 0xff, addr & 0xff))
-               return 0xff;
-       if (system_state == SYSTEM_RUNNING)
-               wait_for_completion(&req_complete);
-       while (!req.complete)
-               pmu_poll();
-       return req.reply[0];
-}
-
-static void pmu_nvram_write_byte(int addr, unsigned char val)
-{
-       struct adb_request req;
-       DECLARE_COMPLETION(req_complete); 
-       
-       req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
-       if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
-                       (addr >> 8) & 0xff, addr & 0xff, val))
-               return;
-       if (system_state == SYSTEM_RUNNING)
-               wait_for_completion(&req_complete);
-       while (!req.complete)
-               pmu_poll();
-}
-
-#endif /* CONFIG_ADB_PMU */
-
-
-static u8 chrp_checksum(struct chrp_header* hdr)
-{
-       u8 *ptr;
-       u16 sum = hdr->signature;
-       for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
-               sum += *ptr;
-       while (sum > 0xFF)
-               sum = (sum & 0xFF) + (sum>>8);
-       return sum;
-}
-
-static u32 core99_calc_adler(u8 *buffer)
-{
-       int cnt;
-       u32 low, high;
-
-       buffer += CORE99_ADLER_START;
-       low = 1;
-       high = 0;
-       for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
-               if ((cnt % 5000) == 0) {
-                       high  %= 65521UL;
-                       high %= 65521UL;
-               }
-               low += buffer[cnt];
-               high += low;
-       }
-       low  %= 65521UL;
-       high %= 65521UL;
-
-       return (high << 16) | low;
-}
-
-static u32 core99_check(u8* datas)
-{
-       struct core99_header* hdr99 = (struct core99_header*)datas;
-
-       if (hdr99->hdr.signature != CORE99_SIGNATURE) {
-               DBG("Invalid signature\n");
-               return 0;
-       }
-       if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
-               DBG("Invalid checksum\n");
-               return 0;
-       }
-       if (hdr99->adler != core99_calc_adler(datas)) {
-               DBG("Invalid adler\n");
-               return 0;
-       }
-       return hdr99->generation;
-}
-
-static int sm_erase_bank(int bank)
-{
-       int stat, i;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
-
-       out_8(base, SM_FLASH_CMD_ERASE_SETUP);
-       out_8(base, SM_FLASH_CMD_ERASE_CONFIRM);
-       timeout = 0;
-       do {
-               if (++timeout > 1000000) {
-                       printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n");
-                       break;
-               }
-               out_8(base, SM_FLASH_CMD_READ_STATUS);
-               stat = in_8(base);
-       } while (!(stat & SM_FLASH_STATUS_DONE));
-
-       out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
-       out_8(base, SM_FLASH_CMD_RESET);
-
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != 0xff) {
-                       printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static int sm_write_bank(int bank, u8* datas)
-{
-       int i, stat = 0;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
-
-       for (i=0; i<NVRAM_SIZE; i++) {
-               out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
-               udelay(1);
-               out_8(base+i, datas[i]);
-               timeout = 0;
-               do {
-                       if (++timeout > 1000000) {
-                               printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n");
-                               break;
-                       }
-                       out_8(base, SM_FLASH_CMD_READ_STATUS);
-                       stat = in_8(base);
-               } while (!(stat & SM_FLASH_STATUS_DONE));
-               if (!(stat & SM_FLASH_STATUS_DONE))
-                       break;
-       }
-       out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
-       out_8(base, SM_FLASH_CMD_RESET);
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != datas[i]) {
-                       printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static int amd_erase_bank(int bank)
-{
-       int i, stat = 0;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: AMD Erasing bank %d...\n", bank);
-
-       /* Unlock 1 */
-       out_8(base+0x555, 0xaa);
-       udelay(1);
-       /* Unlock 2 */
-       out_8(base+0x2aa, 0x55);
-       udelay(1);
-
-       /* Sector-Erase */
-       out_8(base+0x555, 0x80);
-       udelay(1);
-       out_8(base+0x555, 0xaa);
-       udelay(1);
-       out_8(base+0x2aa, 0x55);
-       udelay(1);
-       out_8(base, 0x30);
-       udelay(1);
-
-       timeout = 0;
-       do {
-               if (++timeout > 1000000) {
-                       printk(KERN_ERR "nvram: AMD flash erase timeout !\n");
-                       break;
-               }
-               stat = in_8(base) ^ in_8(base);
-       } while (stat != 0);
-       
-       /* Reset */
-       out_8(base, 0xf0);
-       udelay(1);
-       
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != 0xff) {
-                       printk(KERN_ERR "nvram: AMD flash erase failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static int amd_write_bank(int bank, u8* datas)
-{
-       int i, stat = 0;
-       unsigned long timeout;
-
-       u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
-
-               DBG("nvram: AMD Writing bank %d...\n", bank);
-
-       for (i=0; i<NVRAM_SIZE; i++) {
-               /* Unlock 1 */
-               out_8(base+0x555, 0xaa);
-               udelay(1);
-               /* Unlock 2 */
-               out_8(base+0x2aa, 0x55);
-               udelay(1);
-
-               /* Write single word */
-               out_8(base+0x555, 0xa0);
-               udelay(1);
-               out_8(base+i, datas[i]);
-               
-               timeout = 0;
-               do {
-                       if (++timeout > 1000000) {
-                               printk(KERN_ERR "nvram: AMD flash write timeout !\n");
-                               break;
-                       }
-                       stat = in_8(base) ^ in_8(base);
-               } while (stat != 0);
-               if (stat != 0)
-                       break;
-       }
-
-       /* Reset */
-       out_8(base, 0xf0);
-       udelay(1);
-
-       for (i=0; i<NVRAM_SIZE; i++)
-               if (base[i] != datas[i]) {
-                       printk(KERN_ERR "nvram: AMD flash write failed !\n");
-                       return -ENXIO;
-               }
-       return 0;
-}
-
-static void __init lookup_partitions(void)
-{
-       u8 buffer[17];
-       int i, offset;
-       struct chrp_header* hdr;
-
-       if (pmac_newworld) {
-               nvram_partitions[pmac_nvram_OF] = -1;
-               nvram_partitions[pmac_nvram_XPRAM] = -1;
-               nvram_partitions[pmac_nvram_NR] = -1;
-               hdr = (struct chrp_header *)buffer;
-
-               offset = 0;
-               buffer[16] = 0;
-               do {
-                       for (i=0;i<16;i++)
-                               buffer[i] = nvram_read_byte(offset+i);
-                       if (!strcmp(hdr->name, "common"))
-                               nvram_partitions[pmac_nvram_OF] = offset + 0x10;
-                       if (!strcmp(hdr->name, "APL,MacOS75")) {
-                               nvram_partitions[pmac_nvram_XPRAM] = offset + 0x10;
-                               nvram_partitions[pmac_nvram_NR] = offset + 0x110;
-                       }
-                       offset += (hdr->len * 0x10);
-               } while(offset < NVRAM_SIZE);
-       } else {
-               nvram_partitions[pmac_nvram_OF] = 0x1800;
-               nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
-               nvram_partitions[pmac_nvram_NR] = 0x1400;
-       }
-       DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
-       DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
-       DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
-}
-
-static void core99_nvram_sync(void)
-{
-       struct core99_header* hdr99;
-       unsigned long flags;
-
-       if (!is_core_99 || !nvram_data || !nvram_image)
-               return;
-
-       spin_lock_irqsave(&nv_lock, flags);
-       if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
-               NVRAM_SIZE))
-               goto bail;
-
-       DBG("Updating nvram...\n");
-
-       hdr99 = (struct core99_header*)nvram_image;
-       hdr99->generation++;
-       hdr99->hdr.signature = CORE99_SIGNATURE;
-       hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
-       hdr99->adler = core99_calc_adler(nvram_image);
-       core99_bank = core99_bank ? 0 : 1;
-       if (core99_erase_bank)
-               if (core99_erase_bank(core99_bank)) {
-                       printk("nvram: Error erasing bank %d\n", core99_bank);
-                       goto bail;
-               }
-       if (core99_write_bank)
-               if (core99_write_bank(core99_bank, nvram_image))
-                       printk("nvram: Error writing bank %d\n", core99_bank);
- bail:
-       spin_unlock_irqrestore(&nv_lock, flags);
-
-#ifdef DEBUG
-               mdelay(2000);
-#endif
-}
-
-void __init pmac_nvram_init(void)
-{
-       struct device_node *dp;
-
-       nvram_naddrs = 0;
-
-       dp = find_devices("nvram");
-       if (dp == NULL) {
-               printk(KERN_ERR "Can't find NVRAM device\n");
-               return;
-       }
-       nvram_naddrs = dp->n_addrs;
-       is_core_99 = device_is_compatible(dp, "nvram,flash");
-       if (is_core_99) {
-               int i;
-               u32 gen_bank0, gen_bank1;
-
-               if (nvram_naddrs < 1) {
-                       printk(KERN_ERR "nvram: no address\n");
-                       return;
-               }
-               nvram_image = alloc_bootmem(NVRAM_SIZE);
-               if (nvram_image == NULL) {
-                       printk(KERN_ERR "nvram: can't allocate ram image\n");
-                       return;
-               }
-               nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
-               nvram_naddrs = 1; /* Make sure we get the correct case */
-
-               DBG("nvram: Checking bank 0...\n");
-
-               gen_bank0 = core99_check((u8 *)nvram_data);
-               gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
-               core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
-
-               DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
-               DBG("nvram: Active bank is: %d\n", core99_bank);
-
-               for (i=0; i<NVRAM_SIZE; i++)
-                       nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
-
-               ppc_md.nvram_read_val   = core99_nvram_read_byte;
-               ppc_md.nvram_write_val  = core99_nvram_write_byte;
-               ppc_md.nvram_sync       = core99_nvram_sync;
-               /* 
-                * Maybe we could be smarter here though making an exclusive list
-                * of known flash chips is a bit nasty as older OF didn't provide us
-                * with a useful "compatible" entry. A solution would be to really
-                * identify the chip using flash id commands and base ourselves on
-                * a list of known chips IDs
-                */
-               if (device_is_compatible(dp, "amd-0137")) {
-                       core99_erase_bank = amd_erase_bank;
-                       core99_write_bank = amd_write_bank;
-               } else {
-                       core99_erase_bank = sm_erase_bank;
-                       core99_write_bank = sm_write_bank;
-               }
-       } else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
-               nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
-                                    dp->addrs[0].size);
-               nvram_mult = 1;
-               ppc_md.nvram_read_val   = direct_nvram_read_byte;
-               ppc_md.nvram_write_val  = direct_nvram_write_byte;
-       } else if (nvram_naddrs == 1) {
-               nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-               nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
-               ppc_md.nvram_read_val   = direct_nvram_read_byte;
-               ppc_md.nvram_write_val  = direct_nvram_write_byte;
-       } else if (nvram_naddrs == 2) {
-               nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-               nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
-               ppc_md.nvram_read_val   = indirect_nvram_read_byte;
-               ppc_md.nvram_write_val  = indirect_nvram_write_byte;
-       } else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
-#ifdef CONFIG_ADB_PMU
-               nvram_naddrs = -1;
-               ppc_md.nvram_read_val   = pmu_nvram_read_byte;
-               ppc_md.nvram_write_val  = pmu_nvram_write_byte;
-#endif /* CONFIG_ADB_PMU */
-       } else {
-               printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
-                      nvram_naddrs);
-       }
-       lookup_partitions();
-}
-
-int pmac_get_partition(int partition)
-{
-       return nvram_partitions[partition];
-}
-
-u8 pmac_xpram_read(int xpaddr)
-{
-       int offset = nvram_partitions[pmac_nvram_XPRAM];
-
-       if (offset < 0)
-               return 0xff;
-
-       return ppc_md.nvram_read_val(xpaddr + offset);
-}
-
-void pmac_xpram_write(int xpaddr, u8 data)
-{
-       int offset = nvram_partitions[pmac_nvram_XPRAM];
-
-       if (offset < 0)
-               return;
-
-       ppc_md.nvram_write_val(xpaddr + offset, data);
-}
-
-EXPORT_SYMBOL(pmac_get_partition);
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c
deleted file mode 100644 (file)
index 786295b..0000000
+++ /dev/null
@@ -1,1124 +0,0 @@
-/*
- * Support for PCI bridges found on Power Macintoshes.
- * At present the "bandit" and "chaos" bridges are supported.
- * Fortunately you access configuration space in the same
- * way with either bridge.
- *
- * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#ifdef CONFIG_XMON
-extern void xmon_printf(const char *fmt, ...);
-#define DBG(x...) xmon_printf(x)
-#else
-#define DBG(x...) printk(x)
-#endif
-#else
-#define DBG(x...)
-#endif
-
-static int add_bridge(struct device_node *dev);
-extern void pmac_check_ht_link(void);
-
-/* XXX Could be per-controller, but I don't think we risk anything by
- * assuming we won't have both UniNorth and Bandit */
-static int has_uninorth;
-#ifdef CONFIG_POWER4
-static struct pci_controller *u3_agp;
-#endif /* CONFIG_POWER4 */
-
-extern u8 pci_cache_line_size;
-extern int pcibios_assign_bus_offset;
-
-struct device_node *k2_skiplist[2];
-
-/*
- * Magic constants for enabling cache coherency in the bandit/PSX bridge.
- */
-#define BANDIT_DEVID_2 8
-#define BANDIT_REVID   3
-
-#define BANDIT_DEVNUM  11
-#define BANDIT_MAGIC   0x50
-#define BANDIT_COHERENT        0x40
-
-static int __init
-fixup_one_level_bus_range(struct device_node *node, int higher)
-{
-       for (; node != 0;node = node->sibling) {
-               int * bus_range;
-               unsigned int *class_code;
-               int len;
-
-               /* For PCI<->PCI bridges or CardBus bridges, we go down */
-               class_code = (unsigned int *) 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 = (int *) get_property(node, "bus-range", &len);
-               if (bus_range != NULL && len > 2 * sizeof(int)) {
-                       if (bus_range[1] > higher)
-                               higher = bus_range[1];
-               }
-               higher = fixup_one_level_bus_range(node->child, higher);
-       }
-       return higher;
-}
-
-/* This routine fixes the "bus-range" property of all bridges in the
- * system since they tend to have their "last" member wrong on macs
- *
- * Note that the bus numbers manipulated here are OF bus numbers, they
- * are not Linux bus numbers.
- */
-static void __init
-fixup_bus_range(struct device_node *bridge)
-{
-       int * bus_range;
-       int len;
-
-       /* Lookup the "bus-range" property for the hose */
-       bus_range = (int *) get_property(bridge, "bus-range", &len);
-       if (bus_range == NULL || len < 2 * sizeof(int)) {
-               printk(KERN_WARNING "Can't get bus-range for %s\n",
-                              bridge->full_name);
-               return;
-       }
-       bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
-}
-
-/*
- * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers.
- *
- * The "Bandit" version is present in all early PCI PowerMacs,
- * and up to the first ones using Grackle. Some machines may
- * have 2 bandit controllers (2 PCI busses).
- *
- * "Chaos" is used in some "Bandit"-type machines as a bridge
- * for the separate display bus. It is accessed the same
- * way as bandit, but cannot be probed for devices. It therefore
- * has its own config access functions.
- *
- * The "UniNorth" version is present in all Core99 machines
- * (iBook, G4, new IMacs, and all the recent Apple machines).
- * It contains 3 controllers in one ASIC.
- *
- * The U3 is the bridge used on G5 machines. It contains an
- * AGP bus which is dealt with the old UniNorth access routines
- * and a HyperTransport bus which uses its own set of access
- * functions.
- */
-
-#define MACRISC_CFA0(devfn, off)       \
-       ((1 << (unsigned long)PCI_SLOT(dev_fn)) \
-       | (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
-       | (((unsigned long)(off)) & 0xFCUL))
-
-#define MACRISC_CFA1(bus, devfn, off)  \
-       ((((unsigned long)(bus)) << 16) \
-       |(((unsigned long)(devfn)) << 8) \
-       |(((unsigned long)(off)) & 0xFCUL) \
-       |1UL)
-
-static void volatile __iomem *
-macrisc_cfg_access(struct pci_controller* hose, u8 bus, u8 dev_fn, u8 offset)
-{
-       unsigned int caddr;
-
-       if (bus == hose->first_busno) {
-               if (dev_fn < (11 << 3))
-                       return NULL;
-               caddr = MACRISC_CFA0(dev_fn, offset);
-       } else
-               caddr = MACRISC_CFA1(bus, dev_fn, offset);
-
-       /* Uninorth will return garbage if we don't read back the value ! */
-       do {
-               out_le32(hose->cfg_addr, caddr);
-       } while (in_le32(hose->cfg_addr) != caddr);
-
-       offset &= has_uninorth ? 0x07 : 0x03;
-       return hose->cfg_data + offset;
-}
-
-static int
-macrisc_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                   int len, u32 *val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       void volatile __iomem *addr;
-
-       addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               *val = in_8(addr);
-               break;
-       case 2:
-               *val = in_le16(addr);
-               break;
-       default:
-               *val = in_le32(addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-macrisc_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                    int len, u32 val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       void volatile __iomem *addr;
-
-       addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               out_8(addr, val);
-               (void) in_8(addr);
-               break;
-       case 2:
-               out_le16(addr, val);
-               (void) in_le16(addr);
-               break;
-       default:
-               out_le32(addr, val);
-               (void) in_le32(addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops macrisc_pci_ops =
-{
-       macrisc_read_config,
-       macrisc_write_config
-};
-
-/*
- * Verifiy that a specific (bus, dev_fn) exists on chaos
- */
-static int
-chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
-{
-       struct device_node *np;
-       u32 *vendor, *device;
-
-       np = pci_busdev_to_OF_node(bus, devfn);
-       if (np == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       vendor = (u32 *)get_property(np, "vendor-id", NULL);
-       device = (u32 *)get_property(np, "device-id", NULL);
-       if (vendor == NULL || device == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10)
-           && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24))
-               return PCIBIOS_BAD_REGISTER_NUMBER;
-
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-chaos_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                 int len, u32 *val)
-{
-       int result = chaos_validate_dev(bus, devfn, offset);
-       if (result == PCIBIOS_BAD_REGISTER_NUMBER)
-               *val = ~0U;
-       if (result != PCIBIOS_SUCCESSFUL)
-               return result;
-       return macrisc_read_config(bus, devfn, offset, len, val);
-}
-
-static int
-chaos_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                  int len, u32 val)
-{
-       int result = chaos_validate_dev(bus, devfn, offset);
-       if (result != PCIBIOS_SUCCESSFUL)
-               return result;
-       return macrisc_write_config(bus, devfn, offset, len, val);
-}
-
-static struct pci_ops chaos_pci_ops =
-{
-       chaos_read_config,
-       chaos_write_config
-};
-
-#ifdef CONFIG_POWER4
-
-/*
- * These versions of U3 HyperTransport config space access ops do not
- * implement self-view of the HT host yet
- */
-
-#define U3_HT_CFA0(devfn, off)         \
-               ((((unsigned long)devfn) << 8) | offset)
-#define U3_HT_CFA1(bus, devfn, off)    \
-               (U3_HT_CFA0(devfn, off) \
-               + (((unsigned long)bus) << 16) \
-               + 0x01000000UL)
-
-static void volatile __iomem *
-u3_ht_cfg_access(struct pci_controller* hose, u8 bus, u8 devfn, u8 offset)
-{
-       if (bus == hose->first_busno) {
-               /* For now, we don't self probe U3 HT bridge */
-               if (PCI_FUNC(devfn) != 0 || PCI_SLOT(devfn) > 7 ||
-                   PCI_SLOT(devfn) < 1)
-                       return 0;
-               return hose->cfg_data + U3_HT_CFA0(devfn, offset);
-       } else
-               return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset);
-}
-
-static int
-u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                   int len, u32 *val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       void volatile __iomem *addr;
-       int i;
-
-       struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
-       if (np == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-
-       /*
-        * When a device in K2 is powered down, we die on config
-        * cycle accesses. Fix that here.
-        */
-       for (i=0; i<2; i++)
-               if (k2_skiplist[i] == np) {
-                       switch (len) {
-                       case 1:
-                               *val = 0xff; break;
-                       case 2:
-                               *val = 0xffff; break;
-                       default:
-                               *val = 0xfffffffful; break;
-                       }
-                       return PCIBIOS_SUCCESSFUL;
-               }
-           
-       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               *val = in_8(addr);
-               break;
-       case 2:
-               *val = in_le16(addr);
-               break;
-       default:
-               *val = in_le32(addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-                    int len, u32 val)
-{
-       struct pci_controller *hose = bus->sysdata;
-       void volatile __iomem *addr;
-       int i;
-
-       struct device_node *np = pci_busdev_to_OF_node(bus, devfn);
-       if (np == NULL)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * When a device in K2 is powered down, we die on config
-        * cycle accesses. Fix that here.
-        */
-       for (i=0; i<2; i++)
-               if (k2_skiplist[i] == np)
-                       return PCIBIOS_SUCCESSFUL;
-
-       addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
-       if (!addr)
-               return PCIBIOS_DEVICE_NOT_FOUND;
-       /*
-        * Note: the caller has already checked that offset is
-        * suitably aligned and that len is 1, 2 or 4.
-        */
-       switch (len) {
-       case 1:
-               out_8(addr, val);
-               (void) in_8(addr);
-               break;
-       case 2:
-               out_le16(addr, val);
-               (void) in_le16(addr);
-               break;
-       default:
-               out_le32(addr, val);
-               (void) in_le32(addr);
-               break;
-       }
-       return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops u3_ht_pci_ops =
-{
-       u3_ht_read_config,
-       u3_ht_write_config
-};
-
-#endif /* CONFIG_POWER4 */
-
-/*
- * For a bandit bridge, turn on cache coherency if necessary.
- * N.B. we could clean this up using the hose ops directly.
- */
-static void __init
-init_bandit(struct pci_controller *bp)
-{
-       unsigned int vendev, magic;
-       int rev;
-
-       /* read the word at offset 0 in config space for device 11 */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
-       udelay(2);
-       vendev = in_le32(bp->cfg_data);
-       if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) +
-                       PCI_VENDOR_ID_APPLE) {
-               /* read the revision id */
-               out_le32(bp->cfg_addr,
-                        (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
-               udelay(2);
-               rev = in_8(bp->cfg_data);
-               if (rev != BANDIT_REVID)
-                       printk(KERN_WARNING
-                              "Unknown revision %d for bandit\n", rev);
-       } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) {
-               printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
-               return;
-       }
-
-       /* read the word at offset 0x50 */
-       out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
-       udelay(2);
-       magic = in_le32(bp->cfg_data);
-       if ((magic & BANDIT_COHERENT) != 0)
-               return;
-       magic |= BANDIT_COHERENT;
-       udelay(2);
-       out_le32(bp->cfg_data, magic);
-       printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");
-}
-
-
-/*
- * Tweak the PCI-PCI bridge chip on the blue & white G3s.
- */
-static void __init
-init_p2pbridge(void)
-{
-       struct device_node *p2pbridge;
-       struct pci_controller* hose;
-       u8 bus, devfn;
-       u16 val;
-
-       /* XXX it would be better here to identify the specific
-          PCI-PCI bridge chip we have. */
-       if ((p2pbridge = find_devices("pci-bridge")) == 0
-           || p2pbridge->parent == NULL
-           || strcmp(p2pbridge->parent->name, "pci") != 0)
-               return;
-       if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
-               DBG("Can't find PCI infos for PCI<->PCI bridge\n");
-               return;
-       }
-       /* Warning: At this point, we have not yet renumbered all busses.
-        * So we must use OF walking to find out hose
-        */
-       hose = pci_find_hose_for_OF_device(p2pbridge);
-       if (!hose) {
-               DBG("Can't find hose for PCI<->PCI bridge\n");
-               return;
-       }
-       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;
-       }
-       val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
-       early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
-}
-
-/*
- * Some Apple desktop machines have a NEC PD720100A USB2 controller
- * on the motherboard. Open Firmware, on these, will disable the
- * EHCI part of it so it behaves like a pair of OHCI's. This fixup
- * code re-enables it ;)
- */
-static void __init
-fixup_nec_usb2(void)
-{
-       struct device_node *nec;
-
-       for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
-               struct pci_controller *hose;
-               u32 data, *prop;
-               u8 bus, devfn;
-               
-               prop = (u32 *)get_property(nec, "vendor-id", NULL);
-               if (prop == NULL)
-                       continue;
-               if (0x1033 != *prop)
-                       continue;
-               prop = (u32 *)get_property(nec, "device-id", NULL);
-               if (prop == NULL)
-                       continue;
-               if (0x0035 != *prop)
-                       continue;
-               prop = (u32 *)get_property(nec, "reg", NULL);
-               if (prop == NULL)
-                       continue;
-               devfn = (prop[0] >> 8) & 0xff;
-               bus = (prop[0] >> 16) & 0xff;
-               if (PCI_FUNC(devfn) != 0)
-                       continue;
-               hose = pci_find_hose_for_OF_device(nec);
-               if (!hose)
-                       continue;
-               early_read_config_dword(hose, bus, devfn, 0xe4, &data);
-               if (data & 1UL) {
-                       printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
-                       data &= ~1UL;
-                       early_write_config_dword(hose, bus, devfn, 0xe4, data);
-                       early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
-                               nec->intrs[0].line);
-               }
-       }
-}
-
-void __init
-pmac_find_bridges(void)
-{
-       struct device_node *np, *root;
-       struct device_node *ht = NULL;
-
-       root = of_find_node_by_path("/");
-       if (root == NULL) {
-               printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
-               return;
-       }
-       for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
-               if (np->name == NULL)
-                       continue;
-               if (strcmp(np->name, "bandit") == 0
-                   || strcmp(np->name, "chaos") == 0
-                   || strcmp(np->name, "pci") == 0) {
-                       if (add_bridge(np) == 0)
-                               of_node_get(np);
-               }
-               if (strcmp(np->name, "ht") == 0) {
-                       of_node_get(np);
-                       ht = np;
-               }
-       }
-       of_node_put(root);
-
-       /* Probe HT last as it relies on the agp resources to be already
-        * setup
-        */
-       if (ht && add_bridge(ht) != 0)
-               of_node_put(ht);
-
-       init_p2pbridge();
-       fixup_nec_usb2();
-       
-       /* We are still having some issues with the Xserve G4, enabling
-        * some offset between bus number and domains for now when we
-        * assign all busses should help for now
-        */
-       if (pci_assign_all_buses)
-               pcibios_assign_bus_offset = 0x10;
-
-#ifdef CONFIG_POWER4 
-       /* There is something wrong with DMA on U3/HT. I haven't figured out
-        * the details yet, but if I set the cache line size to 128 bytes like
-        * it should, I'm getting memory corruption caused by devices like
-        * sungem (even without the MWI bit set, but maybe sungem doesn't
-        * care). Right now, it appears that setting up a 64 bytes line size
-        * works properly, 64 bytes beeing the max transfer size of HT, I
-        * suppose this is related the way HT/PCI are hooked together. I still
-        * need to dive into more specs though to be really sure of what's
-        * going on. --BenH.
-        *
-        * Ok, apparently, it's just that HT can't do more than 64 bytes
-        * transactions. MWI seem to be meaningless there as well, it may
-        * be worth nop'ing out pci_set_mwi too though I haven't done that
-        * yet.
-        *
-        * Note that it's a bit different for whatever is in the AGP slot.
-        * For now, I don't care, but this can become a real issue, we
-        * should probably hook pci_set_mwi anyway to make sure it sets
-        * the real cache line size in there.
-        */
-       if (machine_is_compatible("MacRISC4"))
-               pci_cache_line_size = 16; /* 64 bytes */
-
-       pmac_check_ht_link();
-#endif /* CONFIG_POWER4 */
-}
-
-#define GRACKLE_CFA(b, d, o)   (0x80 | ((b) << 8) | ((d) << 16) \
-                                | (((o) & ~3) << 24))
-
-#define GRACKLE_PICR1_STG              0x00000040
-#define GRACKLE_PICR1_LOOPSNOOP                0x00000010
-
-/* N.B. this is called before bridges is initialized, so we can't
-   use grackle_pcibios_{read,write}_config_dword. */
-static inline void grackle_set_stg(struct pci_controller* bp, int enable)
-{
-       unsigned int val;
-
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       val = in_le32(bp->cfg_data);
-       val = enable? (val | GRACKLE_PICR1_STG) :
-               (val & ~GRACKLE_PICR1_STG);
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       out_le32(bp->cfg_data, val);
-       (void)in_le32(bp->cfg_data);
-}
-
-static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
-{
-       unsigned int val;
-
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       val = in_le32(bp->cfg_data);
-       val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) :
-               (val & ~GRACKLE_PICR1_LOOPSNOOP);
-       out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8));
-       out_le32(bp->cfg_data, val);
-       (void)in_le32(bp->cfg_data);
-}
-
-static int __init
-setup_uninorth(struct pci_controller* hose, struct reg_property* addr)
-{
-       pci_assign_all_buses = 1;
-       has_uninorth = 1;
-       hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-       /* We "know" that the bridge at f2000000 has the PCI slots. */
-       return addr->address == 0xf2000000;
-}
-
-static void __init
-setup_bandit(struct pci_controller* hose, struct reg_property* addr)
-{
-       hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-       init_bandit(hose);
-}
-
-static void __init
-setup_chaos(struct pci_controller* hose, struct reg_property* addr)
-{
-       /* assume a `chaos' bridge */
-       hose->ops = &chaos_pci_ops;
-       hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
-}
-
-#ifdef CONFIG_POWER4
-
-static void __init
-setup_u3_agp(struct pci_controller* hose, struct reg_property* addr)
-{
-       /* On G5, we move AGP up to high bus number so we don't need
-        * to reassign bus numbers for HT. If we ever have P2P bridges
-        * on AGP, we'll have to move pci_assign_all_buses to the
-        * pci_controller structure so we enable it for AGP and not for
-        * HT childs.
-        * We hard code the address because of the different size of
-        * the reg address cell, we shall fix that by killing struct
-        * reg_property and using some accessor functions instead
-        */
-               hose->first_busno = 0xf0;
-       hose->last_busno = 0xff;
-       has_uninorth = 1;
-       hose->ops = &macrisc_pci_ops;
-       hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
-       hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
-
-       u3_agp = hose;
-}
-
-static void __init
-setup_u3_ht(struct pci_controller* hose, struct reg_property *addr)
-{
-       struct device_node *np = (struct device_node *)hose->arch_data;
-       int i, cur;
-
-       hose->ops = &u3_ht_pci_ops;
-
-       /* We hard code the address because of the different size of
-        * the reg address cell, we shall fix that by killing struct
-        * reg_property and using some accessor functions instead
-        */
-       hose->cfg_data = ioremap(0xf2000000, 0x02000000);
-
-       /*
-        * /ht node doesn't expose a "ranges" property, so we "remove" regions that
-        * have been allocated to AGP. So far, this version of the code doesn't assign
-        * any of the 0xfxxxxxxx "fine" memory regions to /ht.
-        * We need to fix that sooner or later by either parsing all child "ranges"
-        * properties or figuring out the U3 address space decoding logic and
-        * then read its configuration register (if any).
-        */
-       hose->io_base_phys = 0xf4000000;
-       hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000);
-       isa_io_base = (unsigned long) hose->io_base_virt;
-       hose->io_resource.name = np->full_name;
-       hose->io_resource.start = 0;
-       hose->io_resource.end = 0x003fffff;
-       hose->io_resource.flags = IORESOURCE_IO;
-       hose->pci_mem_offset = 0;
-       hose->first_busno = 0;
-       hose->last_busno = 0xef;
-       hose->mem_resources[0].name = np->full_name;
-       hose->mem_resources[0].start = 0x80000000;
-       hose->mem_resources[0].end = 0xefffffff;
-       hose->mem_resources[0].flags = IORESOURCE_MEM;
-
-       if (u3_agp == NULL) {
-               DBG("U3 has no AGP, using full resource range\n");
-               return;
-       }
-
-       /* We "remove" the AGP resources from the resources allocated to HT, that
-        * is we create "holes". However, that code does assumptions that so far
-        * happen to be true (cross fingers...), typically that resources in the
-        * AGP node are properly ordered
-        */
-       cur = 0;
-       for (i=0; i<3; i++) {
-               struct resource *res = &u3_agp->mem_resources[i];
-               if (res->flags != IORESOURCE_MEM)
-                       continue;
-               /* We don't care about "fine" resources */
-               if (res->start >= 0xf0000000)
-                       continue;
-               /* Check if it's just a matter of "shrinking" us in one direction */
-               if (hose->mem_resources[cur].start == res->start) {
-                       DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
-                           cur, hose->mem_resources[cur].start, res->end + 1);
-                       hose->mem_resources[cur].start = res->end + 1;
-                       continue;
-               }
-               if (hose->mem_resources[cur].end == res->end) {
-                       DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
-                           cur, hose->mem_resources[cur].end, res->start - 1);
-                       hose->mem_resources[cur].end = res->start - 1;
-                       continue;
-               }
-               /* No, it's not the case, we need a hole */
-               if (cur == 2) {
-                       /* not enough resources to make a hole, we drop part of the range */
-                       printk(KERN_WARNING "Running out of resources for /ht host !\n");
-                       hose->mem_resources[cur].end = res->start - 1;
-                       continue;
-               }               
-               cur++;
-                       DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
-                   cur-1, res->start - 1, cur, res->end + 1);
-               hose->mem_resources[cur].name = np->full_name;
-               hose->mem_resources[cur].flags = IORESOURCE_MEM;
-               hose->mem_resources[cur].start = res->end + 1;
-               hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
-               hose->mem_resources[cur-1].end = res->start - 1;
-       }
-}
-
-#endif /* CONFIG_POWER4 */
-
-void __init
-setup_grackle(struct pci_controller *hose)
-{
-       setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
-       if (machine_is_compatible("AAPL,PowerBook1998"))
-               grackle_set_loop_snoop(hose, 1);
-#if 0  /* Disabled for now, HW problems ??? */
-       grackle_set_stg(hose, 1);
-#endif
-}
-
-/*
- * We assume that if we have a G3 powermac, we have one bridge called
- * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
- * if we have one or more bandit or chaos bridges, we don't have a MPC106.
- */
-static int __init
-add_bridge(struct device_node *dev)
-{
-       int len;
-       struct pci_controller *hose;
-       struct reg_property *addr;
-       char* disp_name;
-       int *bus_range;
-       int primary = 1;
-
-       DBG("Adding PCI host bridge %s\n", dev->full_name);
-
-               addr = (struct reg_property *) get_property(dev, "reg", &len);
-               if (addr == NULL || len < sizeof(*addr)) {
-                       printk(KERN_WARNING "Can't use %s: no address\n",
-                              dev->full_name);
-                       return -ENODEV;
-               }
-               bus_range = (int *) 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);
-               }
-
-               hose = pcibios_alloc_controller();
-               if (!hose)
-                       return -ENOMEM;
-               hose->arch_data = dev;
-               hose->first_busno = bus_range ? bus_range[0] : 0;
-               hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
-       disp_name = NULL;
-#ifdef CONFIG_POWER4
-               if (device_is_compatible(dev, "u3-agp")) {
-                       setup_u3_agp(hose, addr);
-                       disp_name = "U3-AGP";
-                       primary = 0;
-               } else if (device_is_compatible(dev, "u3-ht")) {
-                       setup_u3_ht(hose, addr);
-                       disp_name = "U3-HT";
-                       primary = 1;
-               } else
-#endif /* CONFIG_POWER4 */
-       if (device_is_compatible(dev, "uni-north")) {
-                       primary = setup_uninorth(hose, addr);
-                       disp_name = "UniNorth";
-               } else if (strcmp(dev->name, "pci") == 0) {
-                       /* XXX assume this is a mpc106 (grackle) */
-                       setup_grackle(hose);
-                       disp_name = "Grackle (MPC106)";
-               } else if (strcmp(dev->name, "bandit") == 0) {
-                       setup_bandit(hose, addr);
-                       disp_name = "Bandit";
-               } else if (strcmp(dev->name, "chaos") == 0) {
-                       setup_chaos(hose, addr);
-                       disp_name = "Chaos";
-                       primary = 0;
-               }
-               printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
-                       disp_name, addr->address, hose->first_busno, hose->last_busno);
-               DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
-                       hose, hose->cfg_addr, hose->cfg_data);
-
-               /* Interpret the "ranges" property */
-               /* This also maps the I/O region and sets isa_io/mem_base */
-               pci_process_bridge_OF_ranges(hose, dev, primary);
-
-               /* Fixup "bus-range" OF property */
-               fixup_bus_range(dev);
-
-       return 0;
-}
-
-static void __init
-pcibios_fixup_OF_interrupts(void)
-{
-       struct pci_dev* dev = NULL;
-
-       /*
-        * Open Firmware often doesn't initialize the
-        * PCI_INTERRUPT_LINE config register properly, so we
-        * should find the device node and apply the interrupt
-        * obtained from the OF device-tree
-        */
-       for_each_pci_dev(dev) {
-               struct device_node *node;
-               node = pci_device_to_OF_node(dev);
-               /* this is the node, see if it has interrupts */
-               if (node && node->n_intrs > 0)
-                       dev->irq = node->intrs[0].line;
-               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
-       }
-}
-
-void __init
-pmac_pcibios_fixup(void)
-{
-       /* Fixup interrupts according to OF tree */
-       pcibios_fixup_OF_interrupts();
-}
-
-int
-pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
-{
-       struct device_node* node;
-       int updatecfg = 0;
-       int uninorth_child;
-
-       node = pci_device_to_OF_node(dev);
-
-       /* We don't want to enable USB controllers absent from the OF tree
-        * (iBook second controller)
-        */
-       if (dev->vendor == PCI_VENDOR_ID_APPLE
-           && (dev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10))
-           && !node) {
-               printk(KERN_INFO "Apple USB OHCI %s disabled by firmware\n",
-                      pci_name(dev));
-               return -EINVAL;
-       }
-
-       if (!node)
-               return 0;
-
-       uninorth_child = node->parent &&
-               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"))) {
-               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")) {
-               pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
-               updatecfg = 1;
-       }
-
-       if (updatecfg) {
-               u16 cmd;
-       
-               /*
-                * Make sure PCI is correctly configured
-                *
-                * We use old pci_bios versions of the function since, by
-                * default, gmac is not powered up, and so will be absent
-                * from the kernel initial PCI lookup.
-                *
-                * Should be replaced by 2.4 new PCI mechanisms and really
-                * register the device.
-                */
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-               pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
-               pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
-       }
-
-       return 0;
-}
-
-/* We power down some devices after they have been probed. They'll
- * be powered back on later on
- */
-void __init
-pmac_pcibios_after_init(void)
-{
-       struct device_node* nd;
-
-#ifdef CONFIG_BLK_DEV_IDE
-       struct pci_dev *dev = NULL;
-
-       /* OF fails to initialize IDE controllers on macs
-        * (and maybe other machines)
-        *
-        * Ideally, this should be moved to the IDE layer, but we need
-        * to check specifically with Andre Hedrick how to do it cleanly
-        * since the common IDE code seem to care about the fact that the
-        * BIOS may have disabled a controller.
-        *
-        * -- BenH
-        */
-       for_each_pci_dev(dev) {
-               if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE)
-                       pci_enable_device(dev);
-       }
-#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")) {
-                       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"))
-                       pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
-               nd = nd->next;
-       }
-}
-
-void pmac_pci_fixup_cardbus(struct pci_dev* dev)
-{
-       if (_machine != _MACH_Pmac)
-               return;
-       /*
-        * Fix the interrupt routing on the various cardbus bridges
-        * used on powerbooks
-        */
-       if (dev->vendor != PCI_VENDOR_ID_TI)
-               return;
-       if (dev->device == PCI_DEVICE_ID_TI_1130 ||
-           dev->device == PCI_DEVICE_ID_TI_1131) {
-               u8 val;
-               /* Enable PCI interrupt */
-               if (pci_read_config_byte(dev, 0x91, &val) == 0)
-                       pci_write_config_byte(dev, 0x91, val | 0x30);
-               /* Disable ISA interrupt mode */
-               if (pci_read_config_byte(dev, 0x92, &val) == 0)
-                       pci_write_config_byte(dev, 0x92, val & ~0x06);
-       }
-       if (dev->device == PCI_DEVICE_ID_TI_1210 ||
-           dev->device == PCI_DEVICE_ID_TI_1211 ||
-           dev->device == PCI_DEVICE_ID_TI_1410 ||
-           dev->device == PCI_DEVICE_ID_TI_1510) {
-               u8 val;
-               /* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
-                  signal out the MFUNC0 pin */
-               if (pci_read_config_byte(dev, 0x8c, &val) == 0)
-                       pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
-               /* Disable ISA interrupt mode */
-               if (pci_read_config_byte(dev, 0x92, &val) == 0)
-                       pci_write_config_byte(dev, 0x92, val & ~0x06);
-       }
-}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_ANY_ID, pmac_pci_fixup_cardbus);
-
-void pmac_pci_fixup_pciata(struct pci_dev* dev)
-{
-       u8 progif = 0;
-
-       /*
-        * On PowerMacs, we try to switch any PCI ATA controller to
-       * fully native mode
-        */
-       if (_machine != _MACH_Pmac)
-               return;
-       /* Some controllers don't have the class IDE */
-       if (dev->vendor == PCI_VENDOR_ID_PROMISE)
-               switch(dev->device) {
-               case PCI_DEVICE_ID_PROMISE_20246:
-               case PCI_DEVICE_ID_PROMISE_20262:
-               case PCI_DEVICE_ID_PROMISE_20263:
-               case PCI_DEVICE_ID_PROMISE_20265:
-               case PCI_DEVICE_ID_PROMISE_20267:
-               case PCI_DEVICE_ID_PROMISE_20268:
-               case PCI_DEVICE_ID_PROMISE_20269:
-               case PCI_DEVICE_ID_PROMISE_20270:
-               case PCI_DEVICE_ID_PROMISE_20271:
-               case PCI_DEVICE_ID_PROMISE_20275:
-               case PCI_DEVICE_ID_PROMISE_20276:
-               case PCI_DEVICE_ID_PROMISE_20277:
-                       goto good;
-               }
-       /* Others, check PCI class */
-       if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
-               return;
- good:
-       pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-       if ((progif & 5) != 5) {
-               printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
-               (void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
-               if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
-                   (progif & 5) != 5)
-                       printk(KERN_ERR "Rewrite of PROGIF failed !\n");
-       }
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata);
-
-
-/*
- * Disable second function on K2-SATA, it's broken
- * and disable IO BARs on first one
- */
-void pmac_pci_fixup_k2_sata(struct pci_dev* dev)
-{
-       int i;
-       u16 cmd;
-
-       if (PCI_FUNC(dev->devfn) > 0) {
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-               for (i = 0; i < 6; i++) {
-                       dev->resource[i].start = dev->resource[i].end = 0;
-                       dev->resource[i].flags = 0;
-                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
-               }
-       } else {
-               pci_read_config_word(dev, PCI_COMMAND, &cmd);
-               cmd &= ~PCI_COMMAND_IO;
-               pci_write_config_word(dev, PCI_COMMAND, cmd);
-               for (i = 0; i < 5; i++) {
-                       dev->resource[i].start = dev->resource[i].end = 0;
-                       dev->resource[i].flags = 0;
-                       pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
-               }
-       }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS, 0x0240, pmac_pci_fixup_k2_sata);
diff --git a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
deleted file mode 100644 (file)
index 4742bf6..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- *  Support for the interrupt controllers found on Power Macintosh,
- *  currently Apple's "Grand Central" interrupt controller in all
- *  it's incarnations. OpenPIC support used on newer machines is
- *  in a separate file
- *
- *  Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- *  Maintained by 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 Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/sysdev.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/time.h>
-#include <asm/open_pic.h>
-#include <asm/xmon.h>
-#include <asm/pmac_feature.h>
-#include <asm/machdep.h>
-
-#include "pmac_pic.h"
-
-/*
- * XXX this should be in xmon.h, but putting it there means xmon.h
- * has to include <linux/interrupt.h> (to get irqreturn_t), which
- * causes all sorts of problems.  -- paulus
- */
-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
-
-struct pmac_irq_hw {
-        unsigned int    event;
-        unsigned int    enable;
-        unsigned int    ack;
-        unsigned int    level;
-};
-
-/* Default addresses */
-static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
-        (struct pmac_irq_hw *) 0xf3000020,
-        (struct pmac_irq_hw *) 0xf3000010,
-        (struct pmac_irq_hw *) 0xf4000020,
-        (struct pmac_irq_hw *) 0xf4000010,
-};
-
-#define GC_LEVEL_MASK          0x3ff00000
-#define OHARE_LEVEL_MASK       0x1ff00000
-#define HEATHROW_LEVEL_MASK    0x1ff00000
-
-static int max_irqs;
-static int max_real_irqs;
-static u32 level_mask[4];
-
-static DEFINE_SPINLOCK(pmac_pic_lock);
-
-
-#define GATWICK_IRQ_POOL_SIZE        10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
-
-#define NR_MASK_WORDS  ((NR_IRQS + 31) / 32)
-static unsigned long ppc_lost_interrupts[NR_MASK_WORDS];
-
-/*
- * Mark an irq as "lost".  This is only used on the pmac
- * since it can lose interrupts (see pmac_set_irq_mask).
- * -- Cort
- */
-void
-__set_lost(unsigned long irq_nr, int nokick)
-{
-       if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) {
-               atomic_inc(&ppc_n_lost_interrupts);
-               if (!nokick)
-                       set_dec(1);
-       }
-}
-
-static void
-pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
-                atomic_dec(&ppc_n_lost_interrupts);
-       spin_lock_irqsave(&pmac_pic_lock, flags);
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        do {
-                /* make sure ack gets to controller before we enable
-                   interrupts */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-       spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-        unsigned long flags;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-       spin_lock_irqsave(&pmac_pic_lock, flags);
-        /* enable unmasked interrupts */
-        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
-
-        do {
-                /* make sure mask gets to controller before we
-                   return to user */
-                mb();
-        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-                != (ppc_cached_irq_mask[i] & bit));
-
-        /*
-         * Unfortunately, setting the bit in the enable register
-         * when the device interrupt is already on *doesn't* set
-         * the bit in the flag register or request another interrupt.
-         */
-        if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level))
-               __set_lost((ulong)irq_nr, nokicklost);
-       spin_unlock_irqrestore(&pmac_pic_lock, flags);
-}
-
-/* When an irq gets requested for the first client, if it's an
- * edge interrupt, we clear any previous one on the controller
- */
-static unsigned int pmac_startup_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-
-       if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
-               out_le32(&pmac_irq_hw[i]->ack, bit);
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-
-       return 0;
-}
-
-static void pmac_mask_irq(unsigned int irq_nr)
-{
-        clear_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-        mb();
-}
-
-static void pmac_unmask_irq(unsigned int irq_nr)
-{
-        set_bit(irq_nr, ppc_cached_irq_mask);
-        pmac_set_irq_mask(irq_nr, 0);
-}
-
-static void pmac_end_irq(unsigned int irq_nr)
-{
-       if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-           && irq_desc[irq_nr].action) {
-               set_bit(irq_nr, ppc_cached_irq_mask);
-               pmac_set_irq_mask(irq_nr, 1);
-       }
-}
-
-
-struct hw_interrupt_type pmac_pic = {
-       .typename       = " PMAC-PIC ",
-       .startup        = pmac_startup_irq,
-       .enable         = pmac_unmask_irq,
-       .disable        = pmac_mask_irq,
-       .ack            = pmac_mask_and_ack_irq,
-       .end            = pmac_end_irq,
-};
-
-struct hw_interrupt_type gatwick_pic = {
-       .typename       = " GATWICK  ",
-       .startup        = pmac_startup_irq,
-       .enable         = pmac_unmask_irq,
-       .disable        = pmac_mask_irq,
-       .ack            = pmac_mask_and_ack_irq,
-       .end            = pmac_end_irq,
-};
-
-static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       int irq, bits;
-
-       for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) {
-               int i = irq >> 5;
-               bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-               /* We must read level interrupts from the level register */
-               bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-               bits &= ppc_cached_irq_mask[i];
-               if (bits == 0)
-                       continue;
-               irq += __ilog2(bits);
-               __do_IRQ(irq, regs);
-               return IRQ_HANDLED;
-       }
-       printk("gatwick irq not from gatwick pic\n");
-       return IRQ_NONE;
-}
-
-int
-pmac_get_irq(struct pt_regs *regs)
-{
-       int irq;
-       unsigned long bits = 0;
-
-#ifdef CONFIG_SMP
-       void psurge_smp_message_recv(struct pt_regs *);
-
-               /* IPI's are a hack on the powersurge -- Cort */
-               if ( smp_processor_id() != 0 ) {
-               psurge_smp_message_recv(regs);
-               return -2;      /* ignore, already handled */
-        }
-#endif /* CONFIG_SMP */
-       for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
-               int i = irq >> 5;
-               bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i];
-               /* We must read level interrupts from the level register */
-               bits |= (in_le32(&pmac_irq_hw[i]->level) & level_mask[i]);
-               bits &= ppc_cached_irq_mask[i];
-               if (bits == 0)
-                       continue;
-               irq += __ilog2(bits);
-               break;
-       }
-
-       return irq;
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init
-pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
-       struct device_node *node;
-       int count;
-
-       memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-       node = gw->child;
-       count = 0;
-       while(node)
-       {
-               /* Fix SCC */
-               if (strcasecmp(node->name, "escc") == 0)
-                       if (node->child) {
-                               if (node->child->n_intrs < 3) {
-                                       node->child->intrs = &gatwick_int_pool[count];
-                                       count += 3;
-                               }
-                               node->child->n_intrs = 3;
-                               node->child->intrs[0].line = 15+irq_base;
-                               node->child->intrs[1].line =  4+irq_base;
-                               node->child->intrs[2].line =  5+irq_base;
-                               printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-                                       node->child->intrs[0].line,
-                                       node->child->intrs[1].line,
-                                       node->child->intrs[2].line);
-                       }
-               /* Fix media-bay & left SWIM */
-               if (strcasecmp(node->name, "media-bay") == 0) {
-                       struct device_node* ya_node;
-
-                       if (node->n_intrs == 0)
-                               node->intrs = &gatwick_int_pool[count++];
-                       node->n_intrs = 1;
-                       node->intrs[0].line = 29+irq_base;
-                       printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-                                       node->intrs[0].line);
-
-                       ya_node = node->child;
-                       while(ya_node)
-                       {
-                               if (strcasecmp(ya_node->name, "floppy") == 0) {
-                                       if (ya_node->n_intrs < 2) {
-                                               ya_node->intrs = &gatwick_int_pool[count];
-                                               count += 2;
-                                       }
-                                       ya_node->n_intrs = 2;
-                                       ya_node->intrs[0].line = 19+irq_base;
-                                       ya_node->intrs[1].line =  1+irq_base;
-                                       printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
-                                               ya_node->intrs[0].line, ya_node->intrs[1].line);
-                               }
-                               if (strcasecmp(ya_node->name, "ata4") == 0) {
-                                       if (ya_node->n_intrs < 2) {
-                                               ya_node->intrs = &gatwick_int_pool[count];
-                                               count += 2;
-                                       }
-                                       ya_node->n_intrs = 2;
-                                       ya_node->intrs[0].line = 14+irq_base;
-                                       ya_node->intrs[1].line =  3+irq_base;
-                                       printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
-                                               ya_node->intrs[0].line, ya_node->intrs[1].line);
-                               }
-                               ya_node = ya_node->sibling;
-                       }
-               }
-               node = node->sibling;
-       }
-       if (count > 10) {
-               printk("WARNING !! Gatwick interrupt pool overflow\n");
-               printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
-               printk("              requested = %d\n", count);
-       }
-}
-
-/*
- * The PowerBook 3400/2400/3500 can have a combo ethernet/modem
- * card which includes an ohare chip that acts as a second interrupt
- * controller.  If we find this second ohare, set it up and fix the
- * interrupt value in the device tree for the ethernet chip.
- */
-static int __init enable_second_ohare(void)
-{
-       unsigned char bus, devfn;
-       unsigned short cmd;
-        unsigned long addr;
-       struct device_node *irqctrler = find_devices("pci106b,7");
-       struct device_node *ether;
-
-       if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-               return -1;
-       addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
-       pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
-       max_irqs = 64;
-       if (pci_device_from_OF_node(irqctrler, &bus, &devfn) == 0) {
-               struct pci_controller* hose = pci_find_hose_for_OF_device(irqctrler);
-               if (!hose)
-                   printk(KERN_ERR "Can't find PCI hose for OHare2 !\n");
-               else {
-                   early_read_config_word(hose, bus, devfn, PCI_COMMAND, &cmd);
-                   cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
-                   cmd &= ~PCI_COMMAND_IO;
-                   early_write_config_word(hose, bus, devfn, PCI_COMMAND, cmd);
-               }
-       }
-
-       /* Fix interrupt for the modem/ethernet combo controller. The number
-          in the device tree (27) is bogus (correct for the ethernet-only
-          board but not the combo ethernet/modem board).
-          The real interrupt is 28 on the second controller -> 28+32 = 60.
-       */
-       ether = find_devices("pci1011,14");
-       if (ether && ether->n_intrs > 0) {
-               ether->intrs[0].line = 60;
-               printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
-                      ether->intrs[0].line);
-       }
-
-       /* Return the interrupt number of the cascade */
-       return irqctrler->intrs[0].line;
-}
-
-#ifdef CONFIG_POWER4
-static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-       int irq;
-
-       irq = openpic2_get_irq(regs);
-       if (irq != -1)
-               __do_IRQ(irq, regs);
-       return IRQ_HANDLED;
-}
-
-static struct irqaction k2u3_cascade_action = {
-       .handler        = k2u3_action,
-       .flags          = 0,
-       .mask           = CPU_MASK_NONE,
-       .name           = "U3->K2 Cascade",
-};
-#endif /* CONFIG_POWER4 */
-
-#ifdef CONFIG_XMON
-static struct irqaction xmon_action = {
-       .handler        = xmon_irq,
-       .flags          = 0,
-       .mask           = CPU_MASK_NONE,
-       .name           = "NMI - XMON"
-};
-#endif
-
-static struct irqaction gatwick_cascade_action = {
-       .handler        = gatwick_action,
-       .flags          = SA_INTERRUPT,
-       .mask           = CPU_MASK_NONE,
-       .name           = "cascade",
-};
-
-void __init pmac_pic_init(void)
-{
-        int i;
-        struct device_node *irqctrler  = NULL;
-        struct device_node *irqctrler2 = NULL;
-       struct device_node *np;
-        unsigned long addr;
-       int irq_cascade = -1;
-
-       /* We first try to detect Apple's new Core99 chipset, since mac-io
-        * is quite different on those machines and contains an IBM MPIC2.
-        */
-       np = find_type_devices("open-pic");
-       while(np) {
-               if (np->parent && !strcmp(np->parent->name, "u3"))
-                       irqctrler2 = np;
-               else
-                       irqctrler = np;
-               np = np->next;
-       }
-       if (irqctrler != NULL)
-       {
-               if (irqctrler->n_addrs > 0)
-               {
-                       unsigned char senses[128];
-
-                       printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
-                              irqctrler->addrs[0].address);
-
-                       prom_get_irq_senses(senses, 0, 128);
-                       OpenPIC_InitSenses = senses;
-                       OpenPIC_NumInitSenses = 128;
-                       ppc_md.get_irq = openpic_get_irq;
-                       pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
-                       OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
-                                              irqctrler->addrs[0].size);
-                       openpic_init(0);
-
-#ifdef CONFIG_POWER4
-                       if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
-                           irqctrler2->n_addrs > 0) {
-                               printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
-                                      irqctrler2->addrs[0].address,
-                                      irqctrler2->intrs[0].line);
-                               pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
-                               OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address,
-                                                       irqctrler2->addrs[0].size);
-                               prom_get_irq_senses(senses, PMAC_OPENPIC2_OFFSET,
-                                                   PMAC_OPENPIC2_OFFSET+128);
-                               OpenPIC_InitSenses = senses;
-                               OpenPIC_NumInitSenses = 128;
-                               openpic2_init(PMAC_OPENPIC2_OFFSET);
-
-                               if (setup_irq(irqctrler2->intrs[0].line,
-                                             &k2u3_cascade_action))
-                                       printk("Unable to get OpenPIC IRQ for cascade\n");
-                       }
-#endif /* CONFIG_POWER4 */
-
-#ifdef CONFIG_XMON
-                       {
-                               struct device_node* pswitch;
-                               int nmi_irq;
-
-                               pswitch = find_devices("programmer-switch");
-                               if (pswitch && pswitch->n_intrs) {
-                                       nmi_irq = pswitch->intrs[0].line;
-                                       openpic_init_nmi_irq(nmi_irq);
-                                       setup_irq(nmi_irq, &xmon_action);
-                               }
-                       }
-#endif /* CONFIG_XMON */
-                       return;
-               }
-               irqctrler = NULL;
-       }
-
-       /* Get the level/edge settings, assume if it's not
-        * a Grand Central nor an OHare, then it's an Heathrow
-        * (or Paddington).
-        */
-       if (find_devices("gc"))
-               level_mask[0] = GC_LEVEL_MASK;
-       else if (find_devices("ohare")) {
-               level_mask[0] = OHARE_LEVEL_MASK;
-               /* We might have a second cascaded ohare */
-               level_mask[1] = OHARE_LEVEL_MASK;
-       } else {
-               level_mask[0] = HEATHROW_LEVEL_MASK;
-               level_mask[1] = 0;
-               /* We might have a second cascaded heathrow */
-               level_mask[2] = HEATHROW_LEVEL_MASK;
-               level_mask[3] = 0;
-       }
-
-       /*
-        * G3 powermacs and 1999 G3 PowerBooks have 64 interrupts,
-        * 1998 G3 Series PowerBooks have 128,
-        * other powermacs have 32.
-        * The combo ethernet/modem card for the Powerstar powerbooks
-        * (2400/3400/3500, ohare based) has a second ohare chip
-        * effectively making a total of 64.
-        */
-       max_irqs = max_real_irqs = 32;
-       irqctrler = find_devices("mac-io");
-       if (irqctrler)
-       {
-               max_real_irqs = 64;
-               if (irqctrler->next)
-                       max_irqs = 128;
-               else
-                       max_irqs = 64;
-       }
-       for ( i = 0; i < max_real_irqs ; i++ )
-               irq_desc[i].handler = &pmac_pic;
-
-       /* get addresses of first controller */
-       if (irqctrler) {
-               if  (irqctrler->n_addrs > 0) {
-                       addr = (unsigned long)
-                               ioremap(irqctrler->addrs[0].address, 0x40);
-                       for (i = 0; i < 2; ++i)
-                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-                                       (addr + (2 - i) * 0x10);
-               }
-
-               /* get addresses of second controller */
-               irqctrler = irqctrler->next;
-               if (irqctrler && irqctrler->n_addrs > 0) {
-                       addr = (unsigned long)
-                               ioremap(irqctrler->addrs[0].address, 0x40);
-                       for (i = 2; i < 4; ++i)
-                               pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-                                       (addr + (4 - i) * 0x10);
-                       irq_cascade = irqctrler->intrs[0].line;
-                       if (device_is_compatible(irqctrler, "gatwick"))
-                               pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-               }
-       } else {
-               /* older powermacs have a GC (grand central) or ohare at
-                  f3000000, with interrupt control registers at f3000020. */
-               addr = (unsigned long) ioremap(0xf3000000, 0x40);
-               pmac_irq_hw[0] = (volatile struct pmac_irq_hw *) (addr + 0x20);
-       }
-
-       /* PowerBooks 3400 and 3500 can have a second controller in a second
-          ohare chip, on the combo ethernet/modem card */
-       if (machine_is_compatible("AAPL,3400/2400")
-            || machine_is_compatible("AAPL,3500"))
-               irq_cascade = enable_second_ohare();
-
-       /* disable all interrupts in all controllers */
-       for (i = 0; i * 32 < max_irqs; ++i)
-               out_le32(&pmac_irq_hw[i]->enable, 0);
-       /* mark level interrupts */
-       for (i = 0; i < max_irqs; i++)
-               if (level_mask[i >> 5] & (1UL << (i & 0x1f)))
-                       irq_desc[i].status = IRQ_LEVEL;
-
-       /* get interrupt line of secondary interrupt controller */
-       if (irq_cascade >= 0) {
-               printk(KERN_INFO "irq: secondary controller on irq %d\n",
-                       (int)irq_cascade);
-               for ( i = max_real_irqs ; i < max_irqs ; i++ )
-                       irq_desc[i].handler = &gatwick_pic;
-               setup_irq(irq_cascade, &gatwick_cascade_action);
-       }
-       printk("System has %d possible interrupts\n", max_irqs);
-       if (max_irqs != max_real_irqs)
-               printk(KERN_DEBUG "%d interrupts on main controller\n",
-                       max_real_irqs);
-
-#ifdef CONFIG_XMON
-       setup_irq(20, &xmon_action);
-#endif /* CONFIG_XMON */
-}
-
-#ifdef CONFIG_PM
-/*
- * These procedures are used in implementing sleep on the powerbooks.
- * sleep_save_intrs() saves the states of all interrupt enables
- * and disables all interrupts except for the nominated one.
- * sleep_restore_intrs() restores the states of all interrupt enables.
- */
-unsigned long sleep_save_mask[2];
-
-/* This used to be passed by the PMU driver but that link got
- * broken with the new driver model. We use this tweak for now...
- */
-static int pmacpic_find_viaint(void)
-{
-       int viaint = -1;
-
-#ifdef CONFIG_ADB_PMU
-       struct device_node *np;
-
-       if (pmu_get_model() != PMU_OHARE_BASED)
-               goto not_found;
-       np = of_find_node_by_name(NULL, "via-pmu");
-       if (np == NULL)
-               goto not_found;
-       viaint = np->intrs[0].line;
-#endif /* CONFIG_ADB_PMU */
-
-not_found:
-       return viaint;
-}
-
-static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
-{
-       int viaint = pmacpic_find_viaint();
-
-       sleep_save_mask[0] = ppc_cached_irq_mask[0];
-       sleep_save_mask[1] = ppc_cached_irq_mask[1];
-       ppc_cached_irq_mask[0] = 0;
-       ppc_cached_irq_mask[1] = 0;
-       if (viaint > 0)
-               set_bit(viaint, ppc_cached_irq_mask);
-       out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
-       if (max_real_irqs > 32)
-               out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
-       (void)in_le32(&pmac_irq_hw[0]->event);
-       /* make sure mask gets to controller before we return to caller */
-       mb();
-        (void)in_le32(&pmac_irq_hw[0]->enable);
-
-        return 0;
-}
-
-static int pmacpic_resume(struct sys_device *sysdev)
-{
-       int i;
-
-       out_le32(&pmac_irq_hw[0]->enable, 0);
-       if (max_real_irqs > 32)
-               out_le32(&pmac_irq_hw[1]->enable, 0);
-       mb();
-       for (i = 0; i < max_real_irqs; ++i)
-               if (test_bit(i, sleep_save_mask))
-                       pmac_unmask_irq(i);
-
-       return 0;
-}
-
-#endif /* CONFIG_PM */
-
-static struct sysdev_class pmacpic_sysclass = {
-       set_kset_name("pmac_pic"),
-};
-
-static struct sys_device device_pmacpic = {
-       .id             = 0,
-       .cls            = &pmacpic_sysclass,
-};
-
-static struct sysdev_driver driver_pmacpic = {
-#ifdef CONFIG_PM
-       .suspend        = &pmacpic_suspend,
-       .resume         = &pmacpic_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init init_pmacpic_sysfs(void)
-{
-       if (max_irqs == 0)
-               return -ENODEV;
-
-       printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
-       sysdev_class_register(&pmacpic_sysclass);
-       sysdev_register(&device_pmacpic);
-       sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
-       return 0;
-}
-
-subsys_initcall(init_pmacpic_sysfs);
-
diff --git a/arch/ppc/platforms/pmac_pic.h b/arch/ppc/platforms/pmac_pic.h
deleted file mode 100644 (file)
index 664103d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __PPC_PLATFORMS_PMAC_PIC_H
-#define __PPC_PLATFORMS_PMAC_PIC_H
-
-#include <linux/irq.h>
-
-extern struct hw_interrupt_type pmac_pic;
-
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
-
-#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
deleted file mode 100644 (file)
index 55d2bef..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- *  arch/ppc/platforms/setup.c
- *
- *  PowerPC version
- *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- *  Adapted for Power Macintosh by Paul Mackerras
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
- *  Derived from "arch/alpha/kernel/setup.c"
- *    Copyright (C) 1995 Linus Torvalds
- *
- *  Maintained by 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 Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- *
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#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>
-#include <linux/tty.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#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>
-#include <linux/pmu.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#include <linux/bitops.h>
-#include <linux/suspend.h>
-
-#include <asm/reg.h>
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/pci-bridge.h>
-#include <asm/ohare.h>
-#include <asm/mediabay.h>
-#include <asm/machdep.h>
-#include <asm/dma.h>
-#include <asm/bootx.h>
-#include <asm/cputable.h>
-#include <asm/btext.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-#include <asm/of_device.h>
-#include <asm/mmu_context.h>
-
-#include "pmac_pic.h"
-#include "mem_pieces.h"
-
-#undef SHOW_GATWICK_IRQS
-
-extern long pmac_time_init(void);
-extern unsigned long pmac_get_rtc_time(void);
-extern int pmac_set_rtc_time(unsigned long nowtime);
-extern void pmac_read_rtc_time(void);
-extern void pmac_calibrate_decr(void);
-extern void pmac_pcibios_fixup(void);
-extern void pmac_find_bridges(void);
-extern unsigned long pmac_ide_get_base(int index);
-extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
-       unsigned long data_port, unsigned long ctrl_port, int *irq);
-
-extern void pmac_nvram_update(void);
-extern unsigned char pmac_nvram_read_byte(int addr);
-extern void pmac_nvram_write_byte(int addr, unsigned char val);
-extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial);
-extern void pmac_pcibios_after_init(void);
-extern int of_show_percpuinfo(struct seq_file *m, int i);
-
-struct device_node *memory_node;
-
-unsigned char drive_info;
-
-int ppc_override_l2cr = 0;
-int ppc_override_l2cr_value;
-int has_l2cache = 0;
-
-static int current_root_goodness = -1;
-
-extern int pmac_newworld;
-
-#define DEFAULT_ROOT_DEVICE Root_SDA1  /* sda1 - slightly silly choice */
-
-extern void zs_kgdb_hook(int tty_num);
-static void ohare_init(void);
-#ifdef CONFIG_BOOTX_TEXT
-static void pmac_progress(char *s, unsigned short hex);
-#endif
-
-sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
-
-#ifdef CONFIG_SMP
-extern struct smp_ops_t psurge_smp_ops;
-extern struct smp_ops_t core99_smp_ops;
-#endif /* CONFIG_SMP */
-
-static int
-pmac_show_cpuinfo(struct seq_file *m)
-{
-       struct device_node *np;
-       char *pp;
-       int plen;
-       int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-               NULL, PMAC_MB_INFO_MODEL, 0);
-       unsigned int mbflags = (unsigned int)pmac_call_feature(PMAC_FTR_GET_MB_INFO,
-               NULL, PMAC_MB_INFO_FLAGS, 0);
-       char* mbname;
-
-       if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, (int)&mbname) != 0)
-               mbname = "Unknown";
-
-       /* find motherboard type */
-       seq_printf(m, "machine\t\t: ");
-       np = find_devices("device-tree");
-       if (np != NULL) {
-               pp = (char *) get_property(np, "model", NULL);
-               if (pp != NULL)
-                       seq_printf(m, "%s\n", pp);
-               else
-                       seq_printf(m, "PowerMac\n");
-               pp = (char *) get_property(np, "compatible", &plen);
-               if (pp != NULL) {
-                       seq_printf(m, "motherboard\t:");
-                       while (plen > 0) {
-                               int l = strlen(pp) + 1;
-                               seq_printf(m, " %s", pp);
-                               plen -= l;
-                               pp += l;
-                       }
-                       seq_printf(m, "\n");
-               }
-       } else
-               seq_printf(m, "PowerMac\n");
-
-       /* print parsed model */
-       seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
-       seq_printf(m, "pmac flags\t: %08x\n", mbflags);
-
-       /* find l2 cache info */
-       np = find_devices("l2-cache");
-       if (np == 0)
-               np = find_type_devices("cache");
-       if (np != 0) {
-               unsigned int *ic = (unsigned int *)
-                       get_property(np, "i-cache-size", NULL);
-               unsigned int *dc = (unsigned int *)
-                       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) {
-                       seq_printf(m, " %dK unified", *dc / 1024);
-               } else {
-                       if (ic)
-                               seq_printf(m, " %dK instruction", *ic / 1024);
-                       if (dc)
-                               seq_printf(m, "%s %dK data",
-                                          (ic? " +": ""), *dc / 1024);
-               }
-               pp = get_property(np, "ram-type", NULL);
-               if (pp)
-                       seq_printf(m, " %s", pp);
-               seq_printf(m, "\n");
-       }
-
-       /* find ram info */
-       np = find_devices("memory");
-       if (np != 0) {
-               int n;
-               struct reg_property *reg = (struct reg_property *)
-                       get_property(np, "reg", &n);
-
-               if (reg != 0) {
-                       unsigned long total = 0;
-
-                       for (n /= sizeof(struct reg_property); n > 0; --n)
-                               total += (reg++)->size;
-                       seq_printf(m, "memory\t\t: %luMB\n", total >> 20);
-               }
-       }
-
-       /* Checks "l2cr-value" property in the registry */
-       np = find_devices("cpus");
-       if (np == 0)
-               np = find_type_devices("cpu");
-       if (np != 0) {
-               unsigned int *l2cr = (unsigned int *)
-                       get_property(np, "l2cr-value", NULL);
-               if (l2cr != 0) {
-                       seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
-               }
-       }
-
-       /* Indicate newworld/oldworld */
-       seq_printf(m, "pmac-generation\t: %s\n",
-                  pmac_newworld ? "NewWorld" : "OldWorld");
-
-
-       return 0;
-}
-
-static int
-pmac_show_percpuinfo(struct seq_file *m, int i)
-{
-#ifdef CONFIG_CPU_FREQ_PMAC
-       extern unsigned int pmac_get_one_cpufreq(int i);
-       unsigned int freq = pmac_get_one_cpufreq(i);
-       if (freq != 0) {
-               seq_printf(m, "clock\t\t: %dMHz\n", freq/1000);
-               return 0;
-       }
-#endif /* CONFIG_CPU_FREQ_PMAC */
-       return of_show_percpuinfo(m, i);
-}
-
-static volatile u32 *sysctrl_regs;
-
-void __init
-pmac_setup_arch(void)
-{
-       struct device_node *cpu;
-       int *fp;
-       unsigned long pvr;
-
-       pvr = PVR_VER(mfspr(SPRN_PVR));
-
-       /* Set loops_per_jiffy to a half-way reasonable value,
-          for use until calibrate_delay gets called. */
-       cpu = find_type_devices("cpu");
-       if (cpu != 0) {
-               fp = (int *) get_property(cpu, "clock-frequency", NULL);
-               if (fp != 0) {
-                       if (pvr == 4 || pvr >= 8)
-                               /* 604, G3, G4 etc. */
-                               loops_per_jiffy = *fp / HZ;
-                       else
-                               /* 601, 603, etc. */
-                               loops_per_jiffy = *fp / (2*HZ);
-               } else
-                       loops_per_jiffy = 50000000 / HZ;
-       }
-
-       /* this area has the CPU identification register
-          and some registers used by smp boards */
-       sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
-       ohare_init();
-
-       /* Lookup PCI hosts */
-       pmac_find_bridges();
-
-       /* Checks "l2cr-value" property in the registry */
-       if (cpu_has_feature(CPU_FTR_L2CR)) {
-               struct device_node *np = find_devices("cpus");
-               if (np == 0)
-                       np = find_type_devices("cpu");
-               if (np != 0) {
-                       unsigned int *l2cr = (unsigned int *)
-                               get_property(np, "l2cr-value", NULL);
-                       if (l2cr != 0) {
-                               ppc_override_l2cr = 1;
-                               ppc_override_l2cr_value = *l2cr;
-                               _set_L2CR(0);
-                               _set_L2CR(ppc_override_l2cr_value);
-                       }
-               }
-       }
-
-       if (ppc_override_l2cr)
-               printk(KERN_INFO "L2CR overriden (0x%x), backside cache is %s\n",
-                       ppc_override_l2cr_value, (ppc_override_l2cr_value & 0x80000000)
-                               ? "enabled" : "disabled");
-
-#ifdef CONFIG_KGDB
-       zs_kgdb_hook(0);
-#endif
-
-#ifdef CONFIG_ADB_CUDA
-       find_via_cuda();
-#else
-       if (find_devices("via-cuda")) {
-               printk("WARNING ! Your machine is Cuda based but your kernel\n");
-               printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
-       }
-#endif
-#ifdef CONFIG_ADB_PMU
-       find_via_pmu();
-#else
-       if (find_devices("via-pmu")) {
-               printk("WARNING ! Your machine is PMU based but your kernel\n");
-               printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
-       }
-#endif
-#ifdef CONFIG_NVRAM
-       pmac_nvram_init();
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-               ROOT_DEV = DEFAULT_ROOT_DEVICE;
-
-#ifdef CONFIG_SMP
-       /* Check for Core99 */
-       if (find_devices("uni-n") || find_devices("u3"))
-               smp_ops = &core99_smp_ops;
-       else
-               smp_ops = &psurge_smp_ops;
-#endif /* CONFIG_SMP */
-
-       pci_create_OF_bus_map();
-}
-
-static void __init ohare_init(void)
-{
-       /*
-        * Turn on the L2 cache.
-        * We assume that we have a PSX memory controller iff
-        * we have an ohare I/O controller.
-        */
-       if (find_devices("ohare") != NULL) {
-               if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
-                       if (sysctrl_regs[4] & 0x10)
-                               sysctrl_regs[4] |= 0x04000020;
-                       else
-                               sysctrl_regs[4] |= 0x04000000;
-                       if(has_l2cache)
-                               printk(KERN_INFO "Level 2 cache enabled\n");
-               }
-       }
-}
-
-extern char *bootpath;
-extern char *bootdevice;
-void *boot_host;
-int boot_target;
-int boot_part;
-extern dev_t boot_dev;
-
-#ifdef CONFIG_SCSI
-void __init
-note_scsi_host(struct device_node *node, void *host)
-{
-       int l;
-       char *p;
-
-       l = strlen(node->full_name);
-       if (bootpath != NULL && bootdevice != NULL
-           && strncmp(node->full_name, bootdevice, l) == 0
-           && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
-               boot_host = host;
-               /*
-                * There's a bug in OF 1.0.5.  (Why am I not surprised.)
-                * If you pass a path like scsi/sd@1:0 to canon, it returns
-                * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
-                * That is, the scsi target number doesn't get preserved.
-                * So we pick the target number out of bootpath and use that.
-                */
-               p = strstr(bootpath, "/sd@");
-               if (p != NULL) {
-                       p += 4;
-                       boot_target = simple_strtoul(p, NULL, 10);
-                       p = strchr(p, ':');
-                       if (p != NULL)
-                               boot_part = simple_strtoul(p + 1, NULL, 10);
-               }
-       }
-}
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-static dev_t __init
-find_ide_boot(void)
-{
-       char *p;
-       int n;
-       dev_t __init pmac_find_ide_boot(char *bootdevice, int n);
-
-       if (bootdevice == NULL)
-               return 0;
-       p = strrchr(bootdevice, '/');
-       if (p == NULL)
-               return 0;
-       n = p - bootdevice;
-
-       return pmac_find_ide_boot(bootdevice, n);
-}
-#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
-
-static void __init
-find_boot_device(void)
-{
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-       boot_dev = find_ide_boot();
-#endif
-}
-
-static int initializing = 1;
-/* 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, current->active_mm->pgd);
-
-       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,
-};
-
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-
-static int pmac_late_init(void)
-{
-       initializing = 0;
-#ifdef CONFIG_SOFTWARE_SUSPEND
-       pm_set_ops(&pmac_pm_ops);
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-       return 0;
-}
-
-late_initcall(pmac_late_init);
-
-/* can't be __init - can be called whenever a disk is first accessed */
-void
-note_bootable_part(dev_t dev, int part, int goodness)
-{
-       static int found_boot = 0;
-       char *p;
-
-       if (!initializing)
-               return;
-       if ((goodness <= current_root_goodness) &&
-           ROOT_DEV != DEFAULT_ROOT_DEVICE)
-               return;
-       p = strstr(saved_command_line, "root=");
-       if (p != NULL && (p == saved_command_line || p[-1] == ' '))
-               return;
-
-       if (!found_boot) {
-               find_boot_device();
-               found_boot = 1;
-       }
-       if (!boot_dev || dev == boot_dev) {
-               ROOT_DEV = dev + part;
-               boot_dev = 0;
-               current_root_goodness = goodness;
-       }
-}
-
-static void
-pmac_restart(char *cmd)
-{
-#ifdef CONFIG_ADB_CUDA
-       struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               cuda_request(&req, NULL, 2, CUDA_PACKET,
-                            CUDA_RESET_SYSTEM);
-               for (;;)
-                       cuda_poll();
-               break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               pmu_restart();
-               break;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
-       }
-}
-
-static void
-pmac_power_off(void)
-{
-#ifdef CONFIG_ADB_CUDA
-       struct adb_request req;
-#endif /* CONFIG_ADB_CUDA */
-
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               cuda_request(&req, NULL, 2, CUDA_PACKET,
-                            CUDA_POWERDOWN);
-               for (;;)
-                       cuda_poll();
-               break;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               pmu_shutdown();
-               break;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
-       }
-}
-
-static void
-pmac_halt(void)
-{
-   pmac_power_off();
-}
-
-/*
- * Read in a property describing some pieces of memory.
- */
-
-static int __init
-get_mem_prop(char *name, struct mem_pieces *mp)
-{
-       struct reg_property *rp;
-       int i, s;
-       unsigned int *ip;
-       int nac = prom_n_addr_cells(memory_node);
-       int nsc = prom_n_size_cells(memory_node);
-
-       ip = (unsigned int *) get_property(memory_node, name, &s);
-       if (ip == NULL) {
-               printk(KERN_ERR "error: couldn't get %s property on /memory\n",
-                      name);
-               return 0;
-       }
-       s /= (nsc + nac) * 4;
-       rp = mp->regions;
-       for (i = 0; i < s; ++i, ip += nac+nsc) {
-               if (nac >= 2 && ip[nac-2] != 0)
-                       continue;
-               rp->address = ip[nac-1];
-               if (nsc >= 2 && ip[nac+nsc-2] != 0)
-                       rp->size = ~0U;
-               else
-                       rp->size = ip[nac+nsc-1];
-               ++rp;
-       }
-       mp->n_regions = rp - mp->regions;
-
-       /* Make sure the pieces are sorted. */
-       mem_pieces_sort(mp);
-       mem_pieces_coalesce(mp);
-       return 1;
-}
-
-/*
- * On systems with Open Firmware, collect information about
- * physical RAM and which pieces are already in use.
- * At this point, we have (at least) the first 8MB mapped with a BAT.
- * Our text, data, bss use something over 1MB, starting at 0.
- * Open Firmware may be using 1MB at the 4MB point.
- */
-unsigned long __init
-pmac_find_end_of_memory(void)
-{
-       unsigned long a, total;
-       struct mem_pieces phys_mem;
-
-       /*
-        * Find out where physical memory is, and check that it
-        * starts at 0 and is contiguous.  It seems that RAM is
-        * always physically contiguous on Power Macintoshes.
-        *
-        * Supporting discontiguous physical memory isn't hard,
-        * it just makes the virtual <-> physical mapping functions
-        * more complicated (or else you end up wasting space
-        * in mem_map).
-        */
-       memory_node = find_devices("memory");
-       if (memory_node == NULL || !get_mem_prop("reg", &phys_mem)
-           || phys_mem.n_regions == 0)
-               panic("No RAM??");
-       a = phys_mem.regions[0].address;
-       if (a != 0)
-               panic("RAM doesn't start at physical address 0");
-       total = phys_mem.regions[0].size;
-
-       if (phys_mem.n_regions > 1) {
-               printk("RAM starting at 0x%x is not contiguous\n",
-                      phys_mem.regions[1].address);
-               printk("Using RAM from 0 to 0x%lx\n", total-1);
-       }
-
-       return total;
-}
-
-void __init
-pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
-         unsigned long r6, unsigned long r7)
-{
-       /* isa_io_base gets set in pmac_find_bridges */
-       isa_mem_base = PMAC_ISA_MEM_BASE;
-       pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-       ISA_DMA_THRESHOLD = ~0L;
-       DMA_MODE_READ = 1;
-       DMA_MODE_WRITE = 2;
-
-       ppc_md.setup_arch     = pmac_setup_arch;
-       ppc_md.show_cpuinfo   = pmac_show_cpuinfo;
-       ppc_md.show_percpuinfo = pmac_show_percpuinfo;
-       ppc_md.init_IRQ       = pmac_pic_init;
-       ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
-
-       ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
-       ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
-       ppc_md.pcibios_after_init = pmac_pcibios_after_init;
-       ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
-
-       ppc_md.restart        = pmac_restart;
-       ppc_md.power_off      = pmac_power_off;
-       ppc_md.halt           = pmac_halt;
-
-       ppc_md.time_init      = pmac_time_init;
-       ppc_md.set_rtc_time   = pmac_set_rtc_time;
-       ppc_md.get_rtc_time   = pmac_get_rtc_time;
-       ppc_md.calibrate_decr = pmac_calibrate_decr;
-
-       ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-
-       ppc_md.feature_call   = pmac_do_feature_call;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-        ppc_ide_md.ide_init_hwif       = pmac_ide_init_hwif_ports;
-        ppc_ide_md.default_io_base     = pmac_ide_get_base;
-#endif /* CONFIG_BLK_DEV_IDE_PMAC */
-#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
-
-#ifdef CONFIG_BOOTX_TEXT
-       ppc_md.progress = pmac_progress;
-#endif /* CONFIG_BOOTX_TEXT */
-
-       if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
-
-}
-
-#ifdef CONFIG_BOOTX_TEXT
-static void __init
-pmac_progress(char *s, unsigned short hex)
-{
-       if (boot_text_mapped) {
-               btext_drawstring(s);
-               btext_drawchar('\n');
-       }
-}
-#endif /* CONFIG_BOOTX_TEXT */
-
-static int __init
-pmac_declare_of_platform_devices(void)
-{
-       struct device_node *np;
-
-       np = find_devices("uni-n");
-       if (np) {
-               for (np = np->child; np != NULL; np = np->sibling)
-                       if (strncmp(np->name, "i2c", 3) == 0) {
-                               of_platform_device_create(np, "uni-n-i2c",
-                                                         NULL);
-                               break;
-                       }
-       }
-       np = find_devices("u3");
-       if (np) {
-               for (np = np->child; np != NULL; np = np->sibling)
-                       if (strncmp(np->name, "i2c", 3) == 0) {
-                               of_platform_device_create(np, "u3-i2c",
-                                                         NULL);
-                               break;
-                       }
-       }
-
-       np = find_devices("valkyrie");
-       if (np)
-               of_platform_device_create(np, "valkyrie", NULL);
-       np = find_devices("platinum");
-       if (np)
-               of_platform_device_create(np, "platinum", NULL);
-
-       return 0;
-}
-
-device_initcall(pmac_declare_of_platform_devices);
diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S
deleted file mode 100644 (file)
index 22b113d..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * This file contains sleep low-level functions for PowerBook G3.
- *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *    and Paul Mackerras (paulus@samba.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.
- *
- */
-
-#include <linux/config.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/ppc_asm.h>
-#include <asm/cputable.h>
-#include <asm/cache.h>
-#include <asm/thread_info.h>
-#include <asm/asm-offsets.h>
-
-#define MAGIC  0x4c617273      /* 'Lars' */
-
-/*
- * Structure for storing CPU registers on the stack.
- */
-#define SL_SP          0
-#define SL_PC          4
-#define SL_MSR         8
-#define SL_SDR1                0xc
-#define SL_SPRG0       0x10    /* 4 sprg's */
-#define SL_DBAT0       0x20
-#define SL_IBAT0       0x28
-#define SL_DBAT1       0x30
-#define SL_IBAT1       0x38
-#define SL_DBAT2       0x40
-#define SL_IBAT2       0x48
-#define SL_DBAT3       0x50
-#define SL_IBAT3       0x58
-#define SL_TB          0x60
-#define SL_R2          0x68
-#define SL_CR          0x6c
-#define SL_R12         0x70    /* r12 to r31 */
-#define SL_SIZE                (SL_R12 + 80)
-
-       .section .text
-       .align  5
-
-#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
-
-/* This gets called by via-pmu.c late during the sleep process.
- * The PMU was already send the sleep command and will shut us down
- * soon. We need to save all that is needed and setup the wakeup
- * vector that will be called by the ROM on wakeup
- */
-_GLOBAL(low_sleep_handler)
-#ifndef CONFIG_6xx
-       blr
-#else
-       mflr    r0
-       stw     r0,4(r1)
-       stwu    r1,-SL_SIZE(r1)
-       mfcr    r0
-       stw     r0,SL_CR(r1)
-       stw     r2,SL_R2(r1)
-       stmw    r12,SL_R12(r1)
-
-       /* Save MSR & SDR1 */
-       mfmsr   r4
-       stw     r4,SL_MSR(r1)
-       mfsdr1  r4
-       stw     r4,SL_SDR1(r1)
-
-       /* Get a stable timebase and save it */
-1:     mftbu   r4
-       stw     r4,SL_TB(r1)
-       mftb    r5
-       stw     r5,SL_TB+4(r1)
-       mftbu   r3
-       cmpw    r3,r4
-       bne     1b
-
-       /* Save SPRGs */
-       mfsprg  r4,0
-       stw     r4,SL_SPRG0(r1)
-       mfsprg  r4,1
-       stw     r4,SL_SPRG0+4(r1)
-       mfsprg  r4,2
-       stw     r4,SL_SPRG0+8(r1)
-       mfsprg  r4,3
-       stw     r4,SL_SPRG0+12(r1)
-
-       /* Save BATs */
-       mfdbatu r4,0
-       stw     r4,SL_DBAT0(r1)
-       mfdbatl r4,0
-       stw     r4,SL_DBAT0+4(r1)
-       mfdbatu r4,1
-       stw     r4,SL_DBAT1(r1)
-       mfdbatl r4,1
-       stw     r4,SL_DBAT1+4(r1)
-       mfdbatu r4,2
-       stw     r4,SL_DBAT2(r1)
-       mfdbatl r4,2
-       stw     r4,SL_DBAT2+4(r1)
-       mfdbatu r4,3
-       stw     r4,SL_DBAT3(r1)
-       mfdbatl r4,3
-       stw     r4,SL_DBAT3+4(r1)
-       mfibatu r4,0
-       stw     r4,SL_IBAT0(r1)
-       mfibatl r4,0
-       stw     r4,SL_IBAT0+4(r1)
-       mfibatu r4,1
-       stw     r4,SL_IBAT1(r1)
-       mfibatl r4,1
-       stw     r4,SL_IBAT1+4(r1)
-       mfibatu r4,2
-       stw     r4,SL_IBAT2(r1)
-       mfibatl r4,2
-       stw     r4,SL_IBAT2+4(r1)
-       mfibatu r4,3
-       stw     r4,SL_IBAT3(r1)
-       mfibatl r4,3
-       stw     r4,SL_IBAT3+4(r1)
-
-       /* Backup various CPU config stuffs */
-       bl      __save_cpu_setup
-
-       /* The ROM can wake us up via 2 different vectors:
-        *  - On wallstreet & lombard, we must write a magic
-        *    value 'Lars' at address 4 and a pointer to a
-        *    memory location containing the PC to resume from
-        *    at address 0.
-        *  - On Core99, we must store the wakeup vector at
-        *    address 0x80 and eventually it's parameters
-        *    at address 0x84. I've have some trouble with those
-        *    parameters however and I no longer use them.
-        */
-       lis     r5,grackle_wake_up@ha
-       addi    r5,r5,grackle_wake_up@l
-       tophys(r5,r5)
-       stw     r5,SL_PC(r1)
-       lis     r4,KERNELBASE@h
-       tophys(r5,r1)
-       addi    r5,r5,SL_PC
-       lis     r6,MAGIC@ha
-       addi    r6,r6,MAGIC@l
-       stw     r5,0(r4)
-       stw     r6,4(r4)
-       /* Setup stuffs at 0x80-0x84 for Core99 */
-       lis     r3,core99_wake_up@ha
-       addi    r3,r3,core99_wake_up@l
-       tophys(r3,r3)
-       stw     r3,0x80(r4)
-       stw     r5,0x84(r4)
-       /* Store a pointer to our backup storage into
-        * a kernel global
-        */
-       lis r3,sleep_storage@ha
-       addi r3,r3,sleep_storage@l
-       stw r5,0(r3)
-
-       .globl  low_cpu_die
-low_cpu_die:
-       /* Flush & disable all caches */
-       bl      flush_disable_caches
-
-       /* Turn off data relocation. */
-       mfmsr   r3              /* Save MSR in r7 */
-       rlwinm  r3,r3,0,28,26   /* Turn off DR bit */
-       sync
-       mtmsr   r3
-       isync
-
-BEGIN_FTR_SECTION
-       /* Flush any pending L2 data prefetches to work around HW bug */
-       sync
-       lis     r3,0xfff0
-       lwz     r0,0(r3)        /* perform cache-inhibited load to ROM */
-       sync                    /* (caches are disabled at this point) */
-END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
-
-/*
- * Set the HID0 and MSR for sleep.
- */
-       mfspr   r2,SPRN_HID0
-       rlwinm  r2,r2,0,10,7    /* clear doze, nap */
-       oris    r2,r2,HID0_SLEEP@h
-       sync
-       isync
-       mtspr   SPRN_HID0,r2
-       sync
-
-/* This loop puts us back to sleep in case we have a spurrious
- * wakeup so that the host bridge properly stays asleep. The
- * CPU will be turned off, either after a known time (about 1
- * second) on wallstreet & lombard, or as soon as the CPU enters
- * SLEEP mode on core99
- */
-       mfmsr   r2
-       oris    r2,r2,MSR_POW@h
-1:     sync
-       mtmsr   r2
-       isync
-       b       1b
-
-/*
- * Here is the resume code.
- */
-
-
-/*
- * Core99 machines resume here
- * r4 has the physical address of SL_PC(sp) (unused)
- */
-_GLOBAL(core99_wake_up)
-       /* Make sure HID0 no longer contains any sleep bit and that data cache
-        * is disabled
-        */
-       mfspr   r3,SPRN_HID0
-       rlwinm  r3,r3,0,11,7            /* clear SLEEP, NAP, DOZE bits */
-       rlwinm  3,r3,0,18,15            /* clear DCE, ICE */
-       mtspr   SPRN_HID0,r3
-       sync
-       isync
-
-       /* sanitize MSR */
-       mfmsr   r3
-       ori     r3,r3,MSR_EE|MSR_IP
-       xori    r3,r3,MSR_EE|MSR_IP
-       sync
-       isync
-       mtmsr   r3
-       sync
-       isync
-
-       /* Recover sleep storage */
-       lis     r3,sleep_storage@ha
-       addi    r3,r3,sleep_storage@l
-       tophys(r3,r3)
-       lwz     r1,0(r3)
-
-       /* Pass thru to older resume code ... */
-/*
- * Here is the resume code for older machines.
- * r1 has the physical address of SL_PC(sp).
- */
-
-grackle_wake_up:
-
-       /* Restore the kernel's segment registers before
-        * we do any r1 memory access as we are not sure they
-        * are in a sane state above the first 256Mb region
-        */
-       li      r0,16           /* load up segment register values */
-       mtctr   r0              /* for context 0 */
-       lis     r3,0x2000       /* Ku = 1, VSID = 0 */
-       li      r4,0
-3:     mtsrin  r3,r4
-       addi    r3,r3,0x111     /* increment VSID */
-       addis   r4,r4,0x1000    /* address of next segment */
-       bdnz    3b
-       sync
-       isync
-
-       subi    r1,r1,SL_PC
-
-       /* Restore various CPU config stuffs */
-       bl      __restore_cpu_setup
-
-       /* Make sure all FPRs have been initialized */
-       bl      reloc_offset
-       bl      __init_fpu_registers
-
-       /* Invalidate & enable L1 cache, we don't care about
-        * whatever the ROM may have tried to write to memory
-        */
-       bl      __inval_enable_L1
-
-       /* Restore the BATs, and SDR1.  Then we can turn on the MMU. */
-       lwz     r4,SL_SDR1(r1)
-       mtsdr1  r4
-       lwz     r4,SL_SPRG0(r1)
-       mtsprg  0,r4
-       lwz     r4,SL_SPRG0+4(r1)
-       mtsprg  1,r4
-       lwz     r4,SL_SPRG0+8(r1)
-       mtsprg  2,r4
-       lwz     r4,SL_SPRG0+12(r1)
-       mtsprg  3,r4
-
-       lwz     r4,SL_DBAT0(r1)
-       mtdbatu 0,r4
-       lwz     r4,SL_DBAT0+4(r1)
-       mtdbatl 0,r4
-       lwz     r4,SL_DBAT1(r1)
-       mtdbatu 1,r4
-       lwz     r4,SL_DBAT1+4(r1)
-       mtdbatl 1,r4
-       lwz     r4,SL_DBAT2(r1)
-       mtdbatu 2,r4
-       lwz     r4,SL_DBAT2+4(r1)
-       mtdbatl 2,r4
-       lwz     r4,SL_DBAT3(r1)
-       mtdbatu 3,r4
-       lwz     r4,SL_DBAT3+4(r1)
-       mtdbatl 3,r4
-       lwz     r4,SL_IBAT0(r1)
-       mtibatu 0,r4
-       lwz     r4,SL_IBAT0+4(r1)
-       mtibatl 0,r4
-       lwz     r4,SL_IBAT1(r1)
-       mtibatu 1,r4
-       lwz     r4,SL_IBAT1+4(r1)
-       mtibatl 1,r4
-       lwz     r4,SL_IBAT2(r1)
-       mtibatu 2,r4
-       lwz     r4,SL_IBAT2+4(r1)
-       mtibatl 2,r4
-       lwz     r4,SL_IBAT3(r1)
-       mtibatu 3,r4
-       lwz     r4,SL_IBAT3+4(r1)
-       mtibatl 3,r4
-
-BEGIN_FTR_SECTION
-       li      r4,0
-       mtspr   SPRN_DBAT4U,r4
-       mtspr   SPRN_DBAT4L,r4
-       mtspr   SPRN_DBAT5U,r4
-       mtspr   SPRN_DBAT5L,r4
-       mtspr   SPRN_DBAT6U,r4
-       mtspr   SPRN_DBAT6L,r4
-       mtspr   SPRN_DBAT7U,r4
-       mtspr   SPRN_DBAT7L,r4
-       mtspr   SPRN_IBAT4U,r4
-       mtspr   SPRN_IBAT4L,r4
-       mtspr   SPRN_IBAT5U,r4
-       mtspr   SPRN_IBAT5L,r4
-       mtspr   SPRN_IBAT6U,r4
-       mtspr   SPRN_IBAT6L,r4
-       mtspr   SPRN_IBAT7U,r4
-       mtspr   SPRN_IBAT7L,r4
-END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
-
-       /* Flush all TLBs */
-       lis     r4,0x1000
-1:     addic.  r4,r4,-0x1000
-       tlbie   r4
-       blt     1b
-       sync
-
-       /* restore the MSR and turn on the MMU */
-       lwz     r3,SL_MSR(r1)
-       bl      turn_on_mmu
-
-       /* get back the stack pointer */
-       tovirt(r1,r1)
-
-       /* Restore TB */
-       li      r3,0
-       mttbl   r3
-       lwz     r3,SL_TB(r1)
-       lwz     r4,SL_TB+4(r1)
-       mttbu   r3
-       mttbl   r4
-
-       /* Restore the callee-saved registers and return */
-       lwz     r0,SL_CR(r1)
-       mtcr    r0
-       lwz     r2,SL_R2(r1)
-       lmw     r12,SL_R12(r1)
-       addi    r1,r1,SL_SIZE
-       lwz     r0,4(r1)
-       mtlr    r0
-       blr
-
-turn_on_mmu:
-       mflr    r4
-       tovirt(r4,r4)
-       mtsrr0  r4
-       mtsrr1  r3
-       sync
-       isync
-       rfi
-
-#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
-
-       .section .data
-       .balign L1_CACHE_BYTES
-sleep_storage:
-       .long 0
-       .balign L1_CACHE_BYTES, 0
-
-#endif /* CONFIG_6xx */
-       .section .text
diff --git a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
deleted file mode 100644 (file)
index 26ff262..0000000
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * SMP support for power macintosh.
- *
- * We support both the old "powersurge" SMP architecture
- * and the current Core99 (G4 PowerMac) machines.
- *
- * Note that we don't support the very first rev. of
- * Apple/DayStar 2 CPUs board, the one with the funky
- * watchdog. Hopefully, none of these should be there except
- * maybe internally to Apple. I should probably still add some
- * code to detect this card though and disable SMP. --BenH.
- *
- * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
- * and Ben Herrenschmidt <benh@kernel.crashing.org>.
- *
- * Support for DayStar quad CPU cards
- * Copyright (C) XLR8, Inc. 1994-2000
- *
- *  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/config.h>
-#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>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/hardirq.h>
-#include <linux/cpu.h>
-
-#include <asm/ptrace.h>
-#include <asm/atomic.h>
-#include <asm/irq.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/residual.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/time.h>
-#include <asm/open_pic.h>
-#include <asm/cacheflush.h>
-#include <asm/keylargo.h>
-
-/*
- * Powersurge (old powermac SMP) support.
- */
-
-extern void __secondary_start_pmac_0(void);
-
-/* Addresses for powersurge registers */
-#define HAMMERHEAD_BASE                0xf8000000
-#define HHEAD_CONFIG           0x90
-#define HHEAD_SEC_INTR         0xc0
-
-/* register for interrupting the primary processor on the powersurge */
-/* N.B. this is actually the ethernet ROM! */
-#define PSURGE_PRI_INTR                0xf3019000
-
-/* register for storing the start address for the secondary processor */
-/* N.B. this is the PCI config space address register for the 1st bridge */
-#define PSURGE_START           0xf2800000
-
-/* Daystar/XLR8 4-CPU card */
-#define PSURGE_QUAD_REG_ADDR   0xf8800000
-
-#define PSURGE_QUAD_IRQ_SET    0
-#define PSURGE_QUAD_IRQ_CLR    1
-#define PSURGE_QUAD_IRQ_PRIMARY        2
-#define PSURGE_QUAD_CKSTOP_CTL 3
-#define PSURGE_QUAD_PRIMARY_ARB        4
-#define PSURGE_QUAD_BOARD_ID   6
-#define PSURGE_QUAD_WHICH_CPU  7
-#define PSURGE_QUAD_CKSTOP_RDBK        8
-#define PSURGE_QUAD_RESET_CTL  11
-
-#define PSURGE_QUAD_OUT(r, v)  (out_8(quad_base + ((r) << 4) + 4, (v)))
-#define PSURGE_QUAD_IN(r)      (in_8(quad_base + ((r) << 4) + 4) & 0x0f)
-#define PSURGE_QUAD_BIS(r, v)  (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
-#define PSURGE_QUAD_BIC(r, v)  (PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
-
-/* virtual addresses for the above */
-static volatile u8 __iomem *hhead_base;
-static volatile u8 __iomem *quad_base;
-static volatile u32 __iomem *psurge_pri_intr;
-static volatile u8 __iomem *psurge_sec_intr;
-static volatile u32 __iomem *psurge_start;
-
-/* values for psurge_type */
-#define PSURGE_NONE            -1
-#define PSURGE_DUAL            0
-#define PSURGE_QUAD_OKEE       1
-#define PSURGE_QUAD_COTTON     2
-#define PSURGE_QUAD_ICEGRASS   3
-
-/* what sort of powersurge board we have */
-static int psurge_type = PSURGE_NONE;
-
-/* L2 and L3 cache settings to pass from CPU0 to CPU1 */
-volatile static long int core99_l2_cache;
-volatile static long int core99_l3_cache;
-
-/* Timebase freeze GPIO */
-static unsigned int core99_tb_gpio;
-
-/* Sync flag for HW tb sync */
-static volatile int sec_tb_reset = 0;
-static unsigned int pri_tb_hi, pri_tb_lo;
-static unsigned int pri_tb_stamp;
-
-static void __devinit core99_init_caches(int cpu)
-{
-       if (!cpu_has_feature(CPU_FTR_L2CR))
-               return;
-
-       if (cpu == 0) {
-               core99_l2_cache = _get_L2CR();
-               printk("CPU0: L2CR is %lx\n", core99_l2_cache);
-       } else {
-               printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
-               _set_L2CR(0);
-               _set_L2CR(core99_l2_cache);
-               printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
-       }
-
-       if (!cpu_has_feature(CPU_FTR_L3CR))
-               return;
-
-       if (cpu == 0){
-               core99_l3_cache = _get_L3CR();
-               printk("CPU0: L3CR is %lx\n", core99_l3_cache);
-       } else {
-               printk("CPU%d: L3CR was %lx\n", cpu, _get_L3CR());
-               _set_L3CR(0);
-               _set_L3CR(core99_l3_cache);
-               printk("CPU%d: L3CR set to %lx\n", cpu, core99_l3_cache);
-       }
-}
-
-/*
- * Set and clear IPIs for powersurge.
- */
-static inline void psurge_set_ipi(int cpu)
-{
-       if (psurge_type == PSURGE_NONE)
-               return;
-       if (cpu == 0)
-               in_be32(psurge_pri_intr);
-       else if (psurge_type == PSURGE_DUAL)
-               out_8(psurge_sec_intr, 0);
-       else
-               PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
-}
-
-static inline void psurge_clr_ipi(int cpu)
-{
-       if (cpu > 0) {
-               switch(psurge_type) {
-               case PSURGE_DUAL:
-                       out_8(psurge_sec_intr, ~0);
-               case PSURGE_NONE:
-                       break;
-               default:
-                       PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
-               }
-       }
-}
-
-/*
- * On powersurge (old SMP powermac architecture) we don't have
- * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
- *  -- paulus.
- */
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void psurge_smp_message_recv(struct pt_regs *regs)
-{
-       int cpu = smp_processor_id();
-       int msg;
-
-       /* clear interrupt */
-       psurge_clr_ipi(cpu);
-
-       if (num_online_cpus() < 2)
-               return;
-
-       /* make sure there is a message there */
-       for (msg = 0; msg < 4; msg++)
-               if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-                       smp_message_recv(msg, regs);
-}
-
-irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
-{
-       psurge_smp_message_recv(regs);
-       return IRQ_HANDLED;
-}
-
-static void smp_psurge_message_pass(int target, int msg)
-{
-       int i;
-
-       if (num_online_cpus() < 2)
-               return;
-
-       for (i = 0; i < NR_CPUS; i++) {
-               if (!cpu_online(i))
-                       continue;
-               if (target == MSG_ALL
-                   || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
-                   || target == i) {
-                       set_bit(msg, &psurge_smp_message[i]);
-                       psurge_set_ipi(i);
-               }
-       }
-}
-
-/*
- * Determine a quad card presence. We read the board ID register, we
- * force the data bus to change to something else, and we read it again.
- * It it's stable, then the register probably exist (ugh !)
- */
-static int __init psurge_quad_probe(void)
-{
-       int type;
-       unsigned int i;
-
-       type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
-       if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
-           || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-               return PSURGE_DUAL;
-
-       /* looks OK, try a slightly more rigorous test */
-       /* bogus is not necessarily cacheline-aligned,
-          though I don't suppose that really matters.  -- paulus */
-       for (i = 0; i < 100; i++) {
-               volatile u32 bogus[8];
-               bogus[(0+i)%8] = 0x00000000;
-               bogus[(1+i)%8] = 0x55555555;
-               bogus[(2+i)%8] = 0xFFFFFFFF;
-               bogus[(3+i)%8] = 0xAAAAAAAA;
-               bogus[(4+i)%8] = 0x33333333;
-               bogus[(5+i)%8] = 0xCCCCCCCC;
-               bogus[(6+i)%8] = 0xCCCCCCCC;
-               bogus[(7+i)%8] = 0x33333333;
-               wmb();
-               asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
-               mb();
-               if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-                       return PSURGE_DUAL;
-       }
-       return type;
-}
-
-static void __init psurge_quad_init(void)
-{
-       int procbits;
-
-       if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
-       procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
-       if (psurge_type == PSURGE_QUAD_ICEGRASS)
-               PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-       else
-               PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
-       mdelay(33);
-       out_8(psurge_sec_intr, ~0);
-       PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
-       PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-       if (psurge_type != PSURGE_QUAD_ICEGRASS)
-               PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
-       PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
-       mdelay(33);
-       PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
-       mdelay(33);
-       PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
-       mdelay(33);
-}
-
-static int __init smp_psurge_probe(void)
-{
-       int i, ncpus;
-
-       /* We don't do SMP on the PPC601 -- paulus */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-               return 1;
-
-       /*
-        * The powersurge cpu board can be used in the generation
-        * of powermacs that have a socket for an upgradeable cpu card,
-        * including the 7500, 8500, 9500, 9600.
-        * The device tree doesn't tell you if you have 2 cpus because
-        * OF doesn't know anything about the 2nd processor.
-        * Instead we look for magic bits in magic registers,
-        * in the hammerhead memory controller in the case of the
-        * dual-cpu powersurge board.  -- paulus.
-        */
-       if (find_devices("hammerhead") == NULL)
-               return 1;
-
-       hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
-       quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
-       psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
-
-       psurge_type = psurge_quad_probe();
-       if (psurge_type != PSURGE_DUAL) {
-               psurge_quad_init();
-               /* All released cards using this HW design have 4 CPUs */
-               ncpus = 4;
-       } else {
-               iounmap(quad_base);
-               if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
-                       /* not a dual-cpu card */
-                       iounmap(hhead_base);
-                       psurge_type = PSURGE_NONE;
-                       return 1;
-               }
-               ncpus = 2;
-       }
-
-       psurge_start = ioremap(PSURGE_START, 4);
-       psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
-
-       /* this is not actually strictly necessary -- paulus. */
-       for (i = 1; i < ncpus; ++i)
-               smp_hw_index[i] = i;
-
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
-
-       return ncpus;
-}
-
-static void __init smp_psurge_kick_cpu(int nr)
-{
-       unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
-       unsigned long a;
-
-       /* may need to flush here if secondary bats aren't setup */
-       for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
-               asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
-       asm volatile("sync");
-
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
-
-       out_be32(psurge_start, start);
-       mb();
-
-       psurge_set_ipi(nr);
-       udelay(10);
-       psurge_clr_ipi(nr);
-
-       if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-       int t;
-
-       set_dec(tb_ticks_per_jiffy);
-       set_tb(0, 0);
-       last_jiffy_stamp(cpu_nr) = 0;
-
-       if (cpu_nr > 0) {
-               mb();
-               sec_tb_reset = 1;
-               return;
-       }
-
-       /* wait for the secondary to have reset its TB before proceeding */
-       for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-               ;
-
-       /* now interrupt the secondary, starting both TBs */
-       psurge_set_ipi(1);
-
-       smp_tb_synchronized = 1;
-}
-
-static struct irqaction psurge_irqaction = {
-       .handler = psurge_primary_intr,
-       .flags = SA_INTERRUPT,
-       .mask = CPU_MASK_NONE,
-       .name = "primary IPI",
-};
-
-static void __init smp_psurge_setup_cpu(int cpu_nr)
-{
-
-       if (cpu_nr == 0) {
-               /* If we failed to start the second CPU, we should still
-                * send it an IPI to start the timebase & DEC or we might
-                * have them stuck.
-                */
-               if (num_online_cpus() < 2) {
-                       if (psurge_type == PSURGE_DUAL)
-                               psurge_set_ipi(1);
-                       return;
-               }
-               /* reset the entry point so if we get another intr we won't
-                * try to startup again */
-               out_be32(psurge_start, 0x100);
-               if (setup_irq(30, &psurge_irqaction))
-                       printk(KERN_ERR "Couldn't get primary IPI interrupt");
-       }
-
-       if (psurge_type == PSURGE_DUAL)
-               psurge_dual_sync_tb(cpu_nr);
-}
-
-void __init smp_psurge_take_timebase(void)
-{
-       /* Dummy implementation */
-}
-
-void __init smp_psurge_give_timebase(void)
-{
-       /* Dummy implementation */
-}
-
-static int __init smp_core99_probe(void)
-{
-#ifdef CONFIG_6xx
-       extern int powersave_nap;
-#endif
-       struct device_node *cpus, *firstcpu;
-       int i, ncpus = 0, boot_cpu = -1;
-       u32 *tbprop = NULL;
-
-       if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-       cpus = firstcpu = find_type_devices("cpu");
-       while(cpus != NULL) {
-               u32 *regprop = (u32 *)get_property(cpus, "reg", NULL);
-               char *stateprop = (char *)get_property(cpus, "state", NULL);
-               if (regprop != NULL && stateprop != NULL &&
-                   !strncmp(stateprop, "running", 7))
-                       boot_cpu = *regprop;
-               ++ncpus;
-               cpus = cpus->next;
-       }
-       if (boot_cpu == -1)
-               printk(KERN_WARNING "Couldn't detect boot CPU !\n");
-       if (boot_cpu != 0)
-               printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu);
-
-       if (machine_is_compatible("MacRISC4")) {
-               extern struct smp_ops_t core99_smp_ops;
-
-               core99_smp_ops.take_timebase = smp_generic_take_timebase;
-               core99_smp_ops.give_timebase = smp_generic_give_timebase;
-       } else {
-               if (firstcpu != NULL)
-                       tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL);
-               if (tbprop)
-                       core99_tb_gpio = *tbprop;
-               else
-                       core99_tb_gpio = KL_GPIO_TB_ENABLE;
-       }
-
-       if (ncpus > 1) {
-               openpic_request_IPIs();
-               for (i = 1; i < ncpus; ++i)
-                       smp_hw_index[i] = i;
-#ifdef CONFIG_6xx
-               powersave_nap = 0;
-#endif
-               core99_init_caches(0);
-       }
-
-       return ncpus;
-}
-
-static void __devinit smp_core99_kick_cpu(int nr)
-{
-       unsigned long save_vector, new_vector;
-       unsigned long flags;
-
-       volatile unsigned long *vector
-                = ((volatile unsigned long *)(KERNELBASE+0x100));
-       if (nr < 0 || nr > 3)
-               return;
-       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
-
-       local_irq_save(flags);
-       local_irq_disable();
-
-       /* Save reset vector */
-       save_vector = *vector;
-
-       /* Setup fake reset vector that does    
-        *   b __secondary_start_pmac_0 + nr*8 - KERNELBASE
-        */
-       new_vector = (unsigned long) __secondary_start_pmac_0 + nr * 8;
-       *vector = 0x48000002 + new_vector - KERNELBASE;
-
-       /* flush data cache and inval instruction cache */
-       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-
-       /* Put some life in our friend */
-       pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
-
-       /* FIXME: We wait a bit for the CPU to take the exception, I should
-        * instead wait for the entry code to set something for me. Well,
-        * ideally, all that crap will be done in prom.c and the CPU left
-        * in a RAM-based wait loop like CHRP.
-        */
-       mdelay(1);
-
-       /* Restore our exception vector */
-       *vector = save_vector;
-       flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-
-       local_irq_restore(flags);
-       if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
-}
-
-static void __devinit smp_core99_setup_cpu(int cpu_nr)
-{
-       /* Setup L2/L3 */
-       if (cpu_nr != 0)
-               core99_init_caches(cpu_nr);
-
-       /* Setup openpic */
-       do_openpic_setup_cpu();
-
-       if (cpu_nr == 0) {
-#ifdef CONFIG_POWER4
-               extern void g5_phy_disable_cpu1(void);
-
-               /* If we didn't start the second CPU, we must take
-                * it off the bus
-                */
-               if (machine_is_compatible("MacRISC4") &&
-                   num_online_cpus() < 2)              
-                       g5_phy_disable_cpu1();
-#endif /* CONFIG_POWER4 */
-               if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
-       }
-}
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_take_timebase(void)
-{
-       unsigned long flags;
-
-       /* tell the primary we're here */
-       sec_tb_reset = 1;
-       mb();
-
-       /* wait for the primary to set pri_tb_hi/lo */
-       while (sec_tb_reset < 2)
-               mb();
-
-       /* set our stuff the same as the primary */
-       local_irq_save(flags);
-       set_dec(1);
-       set_tb(pri_tb_hi, pri_tb_lo);
-       last_jiffy_stamp(smp_processor_id()) = pri_tb_stamp;
-       mb();
-
-       /* tell the primary we're done */
-               sec_tb_reset = 0;
-       mb();
-       local_irq_restore(flags);
-}
-
-/* not __init, called in sleep/wakeup code */
-void smp_core99_give_timebase(void)
-{
-       unsigned long flags;
-       unsigned int t;
-
-       /* wait for the secondary to be in take_timebase */
-       for (t = 100000; t > 0 && !sec_tb_reset; --t)
-               udelay(10);
-       if (!sec_tb_reset) {
-               printk(KERN_WARNING "Timeout waiting sync on second CPU\n");
-               return;
-       }
-
-       /* freeze the timebase and read it */
-       /* disable interrupts so the timebase is disabled for the
-          shortest possible time */
-       local_irq_save(flags);
-       pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 4);
-       pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-       mb();
-       pri_tb_hi = get_tbu();
-       pri_tb_lo = get_tbl();
-       pri_tb_stamp = last_jiffy_stamp(smp_processor_id());
-       mb();
-
-       /* tell the secondary we're ready */
-       sec_tb_reset = 2;
-       mb();
-
-       /* wait for the secondary to have taken it */
-       for (t = 100000; t > 0 && sec_tb_reset; --t)
-               udelay(10);
-       if (sec_tb_reset)
-               printk(KERN_WARNING "Timeout waiting sync(2) on second CPU\n");
-       else
-               smp_tb_synchronized = 1;
-
-       /* Now, restart the timebase by leaving the GPIO to an open collector */
-               pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, core99_tb_gpio, 0);
-        pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, core99_tb_gpio, 0);
-       local_irq_restore(flags);
-}
-
-
-/* PowerSurge-style Macs */
-struct smp_ops_t psurge_smp_ops = {
-       .message_pass   = smp_psurge_message_pass,
-       .probe          = smp_psurge_probe,
-       .kick_cpu       = smp_psurge_kick_cpu,
-       .setup_cpu      = smp_psurge_setup_cpu,
-       .give_timebase  = smp_psurge_give_timebase,
-       .take_timebase  = smp_psurge_take_timebase,
-};
-
-/* Core99 Macs (dual G4s) */
-struct smp_ops_t core99_smp_ops = {
-       .message_pass   = smp_openpic_message_pass,
-       .probe          = smp_core99_probe,
-       .kick_cpu       = smp_core99_kick_cpu,
-       .setup_cpu      = smp_core99_setup_cpu,
-       .give_timebase  = smp_core99_give_timebase,
-       .take_timebase  = smp_core99_take_timebase,
-};
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-int __cpu_disable(void)
-{
-       cpu_clear(smp_processor_id(), cpu_online_map);
-
-       /* XXX reset cpu affinity here */
-       openpic_set_priority(0xf);
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-       mb();
-       udelay(20);
-       asm volatile("mtdec %0" : : "r" (0x7fffffff));
-       return 0;
-}
-
-extern void low_cpu_die(void) __attribute__((noreturn)); /* in pmac_sleep.S */
-static int cpu_dead[NR_CPUS];
-
-void cpu_die(void)
-{
-       local_irq_disable();
-       cpu_dead[smp_processor_id()] = 1;
-       mb();
-       low_cpu_die();
-}
-
-void __cpu_die(unsigned int cpu)
-{
-       int timeout;
-
-       timeout = 1000;
-       while (!cpu_dead[cpu]) {
-               if (--timeout == 0) {
-                       printk("CPU %u refused to die!\n", cpu);
-                       break;
-               }
-               msleep(1);
-       }
-       cpu_callin_map[cpu] = 0;
-       cpu_dead[cpu] = 0;
-}
-
-#endif
diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
deleted file mode 100644 (file)
index edb9fcc..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Support for periodic interrupts (100 per second) and for getting
- * the current time from the RTC on Power Macintoshes.
- *
- * We use the decrementer register for our periodic interrupts.
- *
- * Paul Mackerras      August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <linux/hardirq.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <asm/nvram.h>
-
-/* Apparently the RTC stores seconds since 1 Jan 1904 */
-#define RTC_OFFSET     2082844800
-
-/*
- * Calibrate the decrementer frequency with the VIA timer 1.
- */
-#define VIA_TIMER_FREQ_6       4700000 /* time 1 frequency * 6 */
-
-/* VIA registers */
-#define RS             0x200           /* skip between registers */
-#define T1CL           (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
-#define T1CH           (5*RS)          /* Timer 1 counter (high 8 bits) */
-#define T1LL           (6*RS)          /* Timer 1 latch (low 8 bits) */
-#define T1LH           (7*RS)          /* Timer 1 latch (high 8 bits) */
-#define ACR            (11*RS)         /* Auxiliary control register */
-#define IFR            (13*RS)         /* Interrupt flag register */
-
-/* Bits in ACR */
-#define T1MODE         0xc0            /* Timer 1 mode */
-#define T1MODE_CONT    0x40            /*  continuous interrupts */
-
-/* Bits in IFR and IER */
-#define T1_INT         0x40            /* Timer 1 interrupt */
-
-extern struct timezone sys_tz;
-
-long __init
-pmac_time_init(void)
-{
-#ifdef CONFIG_NVRAM
-       s32 delta = 0;
-       int dst;
-       
-       delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
-       delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
-       delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
-       if (delta & 0x00800000UL)
-               delta |= 0xFF000000UL;
-       dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
-       printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
-               dst ? "on" : "off");
-       return delta;
-#else
-       return 0;
-#endif
-}
-
-unsigned long
-pmac_get_rtc_time(void)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-       struct adb_request req;
-       unsigned long now;
-#endif
-
-       /* Get the time from the RTC */
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
-                       return 0;
-               while (!req.complete)
-                       cuda_poll();
-               if (req.reply_len != 7)
-                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               now = (req.reply[3] << 24) + (req.reply[4] << 16)
-                       + (req.reply[5] << 8) + req.reply[6];
-               return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
-                       return 0;
-               while (!req.complete)
-                       pmu_poll();
-               if (req.reply_len != 4)
-                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               now = (req.reply[0] << 24) + (req.reply[1] << 16)
-                       + (req.reply[2] << 8) + req.reply[3];
-               return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
-       }
-       return 0;
-}
-
-int
-pmac_set_rtc_time(unsigned long nowtime)
-{
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-       struct adb_request req;
-#endif
-
-       nowtime += RTC_OFFSET;
-
-       switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
-       case SYS_CTRLER_CUDA:
-               if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
-                                nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-                       return 0;
-               while (!req.complete)
-                       cuda_poll();
-               if ((req.reply_len != 3) && (req.reply_len != 7))
-                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               return 1;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-       case SYS_CTRLER_PMU:
-               if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
-                               nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-                       return 0;
-               while (!req.complete)
-                       pmu_poll();
-               if (req.reply_len != 0)
-                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               return 1;
-#endif /* CONFIG_ADB_PMU */
-       default:
-               return 0;
-       }
-}
-
-/*
- * Calibrate the decrementer register using VIA timer 1.
- * This is used both on powermacs and CHRP machines.
- */
-int __init
-via_calibrate_decr(void)
-{
-       struct device_node *vias;
-       volatile unsigned char __iomem *via;
-       int count = VIA_TIMER_FREQ_6 / 100;
-       unsigned int dstart, dend;
-
-       vias = find_devices("via-cuda");
-       if (vias == 0)
-               vias = find_devices("via-pmu");
-       if (vias == 0)
-               vias = find_devices("via");
-       if (vias == 0 || vias->n_addrs == 0)
-               return 0;
-       via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
-
-       /* set timer 1 for continuous interrupts */
-       out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
-       /* set the counter to a small value */
-       out_8(&via[T1CH], 2);
-       /* set the latch to `count' */
-       out_8(&via[T1LL], count);
-       out_8(&via[T1LH], count >> 8);
-       /* wait until it hits 0 */
-       while ((in_8(&via[IFR]) & T1_INT) == 0)
-               ;
-       dstart = get_dec();
-       /* clear the interrupt & wait until it hits 0 again */
-       in_8(&via[T1CL]);
-       while ((in_8(&via[IFR]) & T1_INT) == 0)
-               ;
-       dend = get_dec();
-
-       tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100);
-       tb_to_us = mulhwu_scale_factor(dstart - dend, 60000);
-
-       printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n",
-              tb_ticks_per_jiffy, dstart - dend);
-
-       iounmap(via);
-       
-       return 1;
-}
-
-#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;
-
-       switch (when) {
-       case PBOOK_SLEEP_NOW:
-               do {
-                       seq = read_seqbegin_irqsave(&xtime_lock, flags);
-                       time_diff = xtime.tv_sec - pmac_get_rtc_time();
-               } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-               break;
-       case PBOOK_WAKE:
-               write_seqlock_irqsave(&xtime_lock, flags);
-               xtime.tv_sec = pmac_get_rtc_time() + time_diff;
-               xtime.tv_nsec = 0;
-               last_rtc_update = xtime.tv_sec;
-               write_sequnlock_irqrestore(&xtime_lock, flags);
-               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.
- * This was taken from the pmac time_init() when merging the prep/pmac
- * time functions.
- */
-void __init
-pmac_calibrate_decr(void)
-{
-       struct device_node *cpu;
-       unsigned int freq, *fp;
-
-#ifdef CONFIG_PM
-       pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PM */
-
-       /* We assume MacRISC2 machines have correct device-tree
-        * calibration. That's better since the VIA itself seems
-        * to be slightly off. --BenH
-        */
-       if (!machine_is_compatible("MacRISC2") &&
-           !machine_is_compatible("MacRISC3") &&
-           !machine_is_compatible("MacRISC4"))
-               if (via_calibrate_decr())
-                       return;
-
-       /* Special case: QuickSilver G4s seem to have a badly calibrated
-        * timebase-frequency in OF, VIA is much better on these. We should
-        * probably implement calibration based on the KL timer on these
-        * machines anyway... -BenH
-        */
-       if (machine_is_compatible("PowerMac3,5"))
-               if (via_calibrate_decr())
-                       return;
-       /*
-        * The cpu node should have a timebase-frequency property
-        * to tell us the rate at which the decrementer counts.
-        */
-       cpu = find_type_devices("cpu");
-       if (cpu == 0)
-               panic("can't find cpu node in time_init");
-       fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
-       if (fp == 0)
-               panic("can't get cpu timebase frequency");
-       freq = *fp;
-       printk("time_init: decrementer frequency = %u.%.6u MHz\n",
-              freq/1000000, freq%1000000);
-       tb_ticks_per_jiffy = freq / HZ;
-       tb_to_us = mulhwu_scale_factor(freq, 1000000);
-}
index 84ef03018d0e680b3acc479b4cc9772c88a6adf5..159dcd92a6d129ff8f4514a34c0331f4e6a356f7 100644 (file)
@@ -39,8 +39,6 @@ obj-$(CONFIG_8xx)             += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \
                                   ppc_sys.o mpc8xx_devices.o mpc8xx_sys.o
 obj-$(CONFIG_PCI_QSPAN)                += qspan_pci.o
 obj-$(CONFIG_PPC_OF)           += prom_init.o prom.o
-obj-$(CONFIG_PPC_PMAC)         += open_pic.o
-obj-$(CONFIG_POWER4)           += open_pic2.o
 obj-$(CONFIG_PPC_CHRP)         += open_pic.o
 obj-$(CONFIG_PPC_PREP)         += open_pic.o todc_time.o
 obj-$(CONFIG_BAMBOO)           += pci_auto.o todc_time.o
index 847df4409982af4298af2852920127ab28c2bfee..f9b95de70e230260a6f4e3b7d9cf0655719b90a8 100644 (file)
@@ -28,7 +28,6 @@
  */
 
 struct gianfar_mdio_data mpc83xx_mdio_pdata = {
-       .paddr = 0x24520,
 };
 
 static struct gianfar_platform_data mpc83xx_tsec1_pdata = {
@@ -226,7 +225,14 @@ struct platform_device ppc_sys_platform_devices[] = {
                .name = "fsl-gianfar_mdio",
                .id = 0,
                .dev.platform_data = &mpc83xx_mdio_pdata,
-               .num_resources = 0,
+               .num_resources = 1,
+               .resource = (struct resource[]) {
+                       {
+                               .start  = 0x24520,
+                               .end    = 0x2453f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+               },
        },
 };
 
index 69949d255658c93b76fb24d3d6e52df6f7479a34..00e9b6ff2f6e39f1931ab3cdfdb93e7bac4ebdd9 100644 (file)
@@ -26,7 +26,6 @@
  * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup
  */
 struct gianfar_mdio_data mpc85xx_mdio_pdata = {
-       .paddr = MPC85xx_MIIM_OFFSET,
 };
 
 static struct gianfar_platform_data mpc85xx_tsec1_pdata = {
@@ -720,7 +719,14 @@ struct platform_device ppc_sys_platform_devices[] = {
                .name = "fsl-gianfar_mdio",
                .id = 0,
                .dev.platform_data = &mpc85xx_mdio_pdata,
-               .num_resources = 0,
+               .num_resources = 1,
+               .resource = (struct resource[]) {
+                       {
+                               .start  = 0x24520,
+                               .end    = 0x2453f,
+                               .flags  = IORESOURCE_MEM,
+                       },
+               },
        },
 };
 
index 9ccce438bd7af7ffc1dce54b32377a5975140bcd..ab34b1d6072f6e350c0dfd930c848702ce710157 100644 (file)
@@ -189,6 +189,8 @@ ocp_device_resume(struct device *dev)
 struct bus_type ocp_bus_type = {
        .name = "ocp",
        .match = ocp_device_match,
+       .probe = ocp_driver_probe,
+       .remove = ocp_driver_remove,
        .suspend = ocp_device_suspend,
        .resume = ocp_device_resume,
 };
@@ -210,8 +212,6 @@ ocp_register_driver(struct ocp_driver *drv)
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &ocp_bus_type;
-       drv->driver.probe = ocp_device_probe;
-       drv->driver.remove = ocp_device_remove;
 
        /* register with core */
        return driver_register(&drv->driver);
index af4deace49e0bcf5aab48660ec9a8d88c543495b..482f837fd37359b8dd5dcaab065e6cce1386cb4c 100644 (file)
@@ -70,8 +70,6 @@ int use_of_interrupt_tree;
 struct device_node *dflt_interrupt_controller;
 int num_interrupt_controllers;
 
-int pmac_newworld;
-
 extern unsigned int rtas_entry;  /* physical pointer */
 
 extern struct device_node *allnodes;
@@ -123,22 +121,13 @@ finish_device_tree(void)
        unsigned long mem = (unsigned long) klimit;
        struct device_node *np;
 
-       /* All newworld pmac machines and CHRPs now use the interrupt tree */
+       /* All CHRPs now use the interrupt tree */
        for (np = allnodes; np != NULL; np = np->allnext) {
                if (get_property(np, "interrupt-parent", NULL)) {
                        use_of_interrupt_tree = 1;
                        break;
                }
        }
-       if (_machine == _MACH_Pmac && use_of_interrupt_tree)
-               pmac_newworld = 1;
-
-#ifdef CONFIG_BOOTX_TEXT
-       if (boot_infos && pmac_newworld) {
-               prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
-               prom_print("          You should use an Open Firmware bootloader\n");
-       }
-#endif /* CONFIG_BOOTX_TEXT */
 
        if (use_of_interrupt_tree) {
                /*
@@ -434,16 +423,10 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start)
                 * those machines, we want to offset interrupts from the
                 * second openpic by 128 -- BenH
                 */
-               if (_machine != _MACH_Pmac && num_interrupt_controllers > 1
+               if (num_interrupt_controllers > 1
                    && ic != NULL
                    && get_property(ic, "interrupt-parent", NULL) == NULL)
                        offset = 16;
-               else if (_machine == _MACH_Pmac && num_interrupt_controllers > 1
-                        && ic != NULL && ic->parent != NULL) {
-                       char *name = get_property(ic->parent, "name", NULL);
-                       if (name && !strcmp(name, "u3"))
-                               offset = 128;
-               }
 
                np->intrs[i].line = irq[0] + offset;
                if (n > 1)
index c80177f8ec04e1f1fa6cc32fed12e90a6c3d26d9..4344cbe9b5c5238c98dd66818e9ac6e5d8832a5a 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/errno.h>
-#include <asm/pmac_feature.h>
 #include <asm/processor.h>
 #include <asm/delay.h>
 #include <asm/btext.h>
@@ -27,11 +26,9 @@ static volatile unsigned char *sccc, *sccd;
 unsigned int TXRDY, RXRDY, DLAB;
 static int xmon_expect(const char *str, unsigned int timeout);
 
-static int use_serial;
 static int use_screen;
 static int via_modem;
 static int xmon_use_sccb;
-static struct device_node *channel_node;
 
 #define TB_SPEED       25000000
 
@@ -112,96 +109,21 @@ xmon_map_scc(void)
 #ifdef CONFIG_PPC_MULTIPLATFORM
        volatile unsigned char *base;
 
-       if (_machine == _MACH_Pmac) {
-               struct device_node *np;
-               unsigned long addr;
-#ifdef CONFIG_BOOTX_TEXT
-               if (!use_screen && !use_serial
-                   && !machine_is_compatible("iMac")) {
-                       /* see if there is a keyboard in the device tree
-                          with a parent of type "adb" */
-                       for (np = find_devices("keyboard"); np; np = np->next)
-                               if (np->parent && np->parent->type
-                                   && strcmp(np->parent->type, "adb") == 0)
-                                       break;
-
-                       /* needs to be hacked if xmon_printk is to be used
-                          from within find_via_pmu() */
-#ifdef CONFIG_ADB_PMU
-                       if (np != NULL && boot_text_mapped && find_via_pmu())
-                               use_screen = 1;
-#endif
-#ifdef CONFIG_ADB_CUDA
-                       if (np != NULL && boot_text_mapped && find_via_cuda())
-                               use_screen = 1;
-#endif
-               }
-               if (!use_screen && (np = find_devices("escc")) != NULL) {
-                       /*
-                        * look for the device node for the serial port
-                        * we're using and see if it says it has a modem
-                        */
-                       char *name = xmon_use_sccb? "ch-b": "ch-a";
-                       char *slots;
-                       int l;
-
-                       np = np->child;
-                       while (np != NULL && strcmp(np->name, name) != 0)
-                               np = np->sibling;
-                       if (np != NULL) {
-                               /* XXX should parse this properly */
-                               channel_node = np;
-                               slots = get_property(np, "slot-names", &l);
-                               if (slots != NULL && l >= 10
-                                   && strcmp(slots+4, "Modem") == 0)
-                                       via_modem = 1;
-                       }
-               }
-               btext_drawstring("xmon uses ");
-               if (use_screen)
-                       btext_drawstring("screen and keyboard\n");
-               else {
-                       if (via_modem)
-                               btext_drawstring("modem on ");
-                       btext_drawstring(xmon_use_sccb? "printer": "modem");
-                       btext_drawstring(" port\n");
-               }
-
-#endif /* CONFIG_BOOTX_TEXT */
-
-#ifdef CHRP_ESCC
-               addr = 0xc1013020;
-#else
-               addr = 0xf3013020;
-#endif
-               TXRDY = 4;
-               RXRDY = 1;
-       
-               np = find_devices("mac-io");
-               if (np && np->n_addrs)
-                       addr = np->addrs[0].address + 0x13020;
-               base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE);
-               sccc = base + (addr & ~PAGE_MASK);
-               sccd = sccc + 0x10;
-
-       }
 #ifdef CONFIG_PPC_CHRP
-       else {
-               base = (volatile unsigned char *) isa_io_base;
-               if (_machine == _MACH_chrp)
-                       base = (volatile unsigned char *)
-                               ioremap(chrp_find_phys_io_base(), 0x1000);
-
-               sccc = base + 0x3fd;
-               sccd = base + 0x3f8;
-               if (xmon_use_sccb) {
-                       sccc -= 0x100;
-                       sccd -= 0x100;
-               }
-               TXRDY = 0x20;
-               RXRDY = 1;
-               DLAB = 0x80;
+       base = (volatile unsigned char *) isa_io_base;
+       if (_machine == _MACH_chrp)
+               base = (volatile unsigned char *)
+                       ioremap(chrp_find_phys_io_base(), 0x1000);
+
+       sccc = base + 0x3fd;
+       sccd = base + 0x3f8;
+       if (xmon_use_sccb) {
+               sccc -= 0x100;
+               sccd -= 0x100;
        }
+       TXRDY = 0x20;
+       RXRDY = 1;
+       DLAB = 0x80;
 #endif /* CONFIG_PPC_CHRP */
 #elif defined(CONFIG_GEMINI)
        /* should already be mapped by the kernel boot */
@@ -385,16 +307,6 @@ xmon_read_poll(void)
        return *sccd;
 }
 
-static unsigned char scc_inittab[] = {
-    13, 0,             /* set baud rate divisor */
-    12, 1,
-    14, 1,             /* baud rate gen enable, src=rtxc */
-    11, 0x50,          /* clocks = br gen */
-    5,  0xea,          /* tx 8 bits, assert DTR & RTS */
-    4,  0x46,          /* x16 clock, 1 stop */
-    3,  0xc1,          /* rx enable, 8 bits */
-};
-
 void
 xmon_init_scc(void)
 {
@@ -407,43 +319,6 @@ xmon_init_scc(void)
                sccd[3] = 3; eieio();           /* LCR = 8N1 */
                sccd[1] = 0; eieio();           /* IER = 0 */
        }
-       else if ( _machine == _MACH_Pmac )
-       {
-               int i, x;
-
-               if (channel_node != 0)
-                       pmac_call_feature(
-                               PMAC_FTR_SCC_ENABLE,
-                               channel_node,
-                               PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
-                       printk(KERN_INFO "Serial port locked ON by debugger !\n");
-               if (via_modem && channel_node != 0) {
-                       unsigned int t0;
-
-                       pmac_call_feature(
-                               PMAC_FTR_MODEM_ENABLE,
-                               channel_node, 0, 1);
-                       printk(KERN_INFO "Modem powered up by debugger !\n");
-                       t0 = readtb();
-                       while (readtb() - t0 < 3*TB_SPEED)
-                               eieio();
-               }
-               /* use the B channel if requested */
-               if (xmon_use_sccb) {
-                       sccc = (volatile unsigned char *)
-                               ((unsigned long)sccc & ~0x20);
-                       sccd = sccc + 0x10;
-               }
-               for (i = 20000; i != 0; --i) {
-                       x = *sccc; eieio();
-               }
-               *sccc = 9; eieio();             /* reset A or B side */
-               *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio();
-               for (i = 0; i < sizeof(scc_inittab); ++i) {
-                       *sccc = scc_inittab[i];
-                       eieio();
-               }
-       }
        scc_initialized = 1;
        if (via_modem) {
                for (;;) {
@@ -632,19 +507,9 @@ xmon_fgets(char *str, int nb, void *f)
 void
 xmon_enter(void)
 {
-#ifdef CONFIG_ADB_PMU
-       if (_machine == _MACH_Pmac) {
-               pmu_suspend();
-       }
-#endif
 }
 
 void
 xmon_leave(void)
 {
-#ifdef CONFIG_ADB_PMU
-       if (_machine == _MACH_Pmac) {
-               pmu_resume();
-       }
-#endif
 }
index 9075a7538e26410d83bb33a50f822816b26e76bb..bdaf6597b4c202c122f4b4be38fcf5b97f97ddf7 100644 (file)
@@ -16,9 +16,6 @@
 #include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
 #include "nonstdio.h"
 #include "privinst.h"
 
@@ -260,16 +257,6 @@ int xmon(struct pt_regs *excp)
         */
 #endif /* CONFIG_SMP */
        remove_bpts();
-#ifdef CONFIG_PMAC_BACKLIGHT
-       if( setjmp(bus_error_jmp) == 0 ) {
-               debugger_fault_handler = handle_fault;
-               sync();
-               set_backlight_enable(1);
-               set_backlight_level(BACKLIGHT_MAX);
-               sync();
-       }
-       debugger_fault_handler = NULL;
-#endif /* CONFIG_PMAC_BACKLIGHT */
        cmd = cmds(excp);
        if (cmd == 's') {
                xmon_trace[smp_processor_id()] = SSTEP;
index 7a1033d8e00fe202ed15245b610f1455baf53f61..c5ca2dc5d4281ee67d7d67be936dec4ec2214ff0 100644 (file)
@@ -114,80 +114,108 @@ static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
                                    const u8 *in, unsigned int nbytes)
 {
        struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(AES_BLOCK_SIZE - 1);
 
        switch (sctx->key_len) {
        case 16:
-               crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, nbytes);
+               ret = crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 24:
-               crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in, nbytes);
+               ret = crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 32:
-               crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in, nbytes);
+               ret = crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        }
-       return nbytes & ~(AES_BLOCK_SIZE - 1);
+       return nbytes;
 }
 
 static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
                                    const u8 *in, unsigned int nbytes)
 {
        struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(AES_BLOCK_SIZE - 1);
 
        switch (sctx->key_len) {
        case 16:
-               crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, nbytes);
+               ret = crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 24:
-               crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in, nbytes);
+               ret = crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 32:
-               crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in, nbytes);
+               ret = crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        }
-       return nbytes & ~(AES_BLOCK_SIZE - 1);
+       return nbytes;
 }
 
 static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
                                    const u8 *in, unsigned int nbytes)
 {
        struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(AES_BLOCK_SIZE - 1);
 
        memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE);
        switch (sctx->key_len) {
        case 16:
-               crypt_s390_kmc(KMC_AES_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+               ret = crypt_s390_kmc(KMC_AES_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 24:
-               crypt_s390_kmc(KMC_AES_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+               ret = crypt_s390_kmc(KMC_AES_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 32:
-               crypt_s390_kmc(KMC_AES_256_ENCRYPT, &sctx->iv, out, in, nbytes);
+               ret = crypt_s390_kmc(KMC_AES_256_ENCRYPT, &sctx->iv, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        }
        memcpy(desc->info, &sctx->iv, AES_BLOCK_SIZE);
 
-       return nbytes & ~(AES_BLOCK_SIZE - 1);
+       return nbytes;
 }
 
 static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
                                    const u8 *in, unsigned int nbytes)
 {
        struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(AES_BLOCK_SIZE - 1);
 
        memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE);
        switch (sctx->key_len) {
        case 16:
-               crypt_s390_kmc(KMC_AES_128_DECRYPT, &sctx->iv, out, in, nbytes);
+               ret = crypt_s390_kmc(KMC_AES_128_DECRYPT, &sctx->iv, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 24:
-               crypt_s390_kmc(KMC_AES_192_DECRYPT, &sctx->iv, out, in, nbytes);
+               ret = crypt_s390_kmc(KMC_AES_192_DECRYPT, &sctx->iv, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        case 32:
-               crypt_s390_kmc(KMC_AES_256_DECRYPT, &sctx->iv, out, in, nbytes);
+               ret = crypt_s390_kmc(KMC_AES_256_DECRYPT, &sctx->iv, out, in, nbytes);
+               BUG_ON((ret < 0) || (ret != nbytes));
                break;
        }
-       return nbytes & ~(AES_BLOCK_SIZE - 1);
+       return nbytes;
 }
 
 
index a38bb2a3eef602e105f0114d54ad875c276a6b1e..e3c37aa0a19936b33be3e4a2b13a067129d29e7d 100644 (file)
  */
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <asm/scatterlist.h>
 #include <linux/crypto.h>
+
 #include "crypt_s390.h"
 #include "crypto_des.h"
 
@@ -46,38 +44,92 @@ struct crypt_s390_des3_192_ctx {
        u8 key[DES3_192_KEY_SIZE];
 };
 
-static int
-des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des_setkey(void *ctx, const u8 *key, unsigned int keylen,
+                     u32 *flags)
 {
-       struct crypt_s390_des_ctx *dctx;
+       struct crypt_s390_des_ctx *dctx = ctx;
        int ret;
 
-       dctx = ctx;
-       //test if key is valid (not a weak key)
+       /* test if key is valid (not a weak key) */
        ret = crypto_des_check_key(key, keylen, flags);
-       if (ret == 0){
+       if (ret == 0)
                memcpy(dctx->key, key, keylen);
-       }
        return ret;
 }
 
+static void des_encrypt(void *ctx, u8 *out, const u8 *in)
+{
+       struct crypt_s390_des_ctx *dctx = ctx;
+
+       crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+}
+
+static void des_decrypt(void *ctx, u8 *out, const u8 *in)
+{
+       struct crypt_s390_des_ctx *dctx = ctx;
+
+       crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+}
+
+static unsigned int des_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
+                                   const u8 *in, unsigned int nbytes)
+{
+       struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES_BLOCK_SIZE - 1);
+       ret = crypt_s390_km(KM_DEA_ENCRYPT, sctx->key, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
+}
 
-static void
-des_encrypt(void *ctx, u8 *dst, const u8 *src)
+static unsigned int des_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+                                   const u8 *in, unsigned int nbytes)
 {
-       struct crypt_s390_des_ctx *dctx;
+       struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES_BLOCK_SIZE - 1);
+       ret = crypt_s390_km(KM_DEA_DECRYPT, sctx->key, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
 
-       dctx = ctx;
-       crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, dst, src, DES_BLOCK_SIZE);
+       return nbytes;
 }
 
-static void
-des_decrypt(void *ctx, u8 *dst, const u8 *src)
+static unsigned int des_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
+                                   const u8 *in, unsigned int nbytes)
 {
-       struct crypt_s390_des_ctx *dctx;
+       struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
 
-       dctx = ctx;
-       crypt_s390_km(KM_DEA_DECRYPT, dctx->key, dst, src, DES_BLOCK_SIZE);
+       /* only use complete blocks */
+       nbytes &= ~(DES_BLOCK_SIZE - 1);
+
+       memcpy(sctx->iv, desc->info, DES_BLOCK_SIZE);
+       ret = crypt_s390_kmc(KMC_DEA_ENCRYPT, &sctx->iv, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       memcpy(desc->info, sctx->iv, DES_BLOCK_SIZE);
+       return nbytes;
+}
+
+static unsigned int des_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+                                   const u8 *in, unsigned int nbytes)
+{
+       struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES_BLOCK_SIZE - 1);
+
+       memcpy(&sctx->iv, desc->info, DES_BLOCK_SIZE);
+       ret = crypt_s390_kmc(KMC_DEA_DECRYPT, &sctx->iv, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
 }
 
 static struct crypto_alg des_alg = {
@@ -87,12 +139,19 @@ static struct crypto_alg des_alg = {
        .cra_ctxsize            =       sizeof(struct crypt_s390_des_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(des_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       DES_KEY_SIZE,
-       .cia_max_keysize        =       DES_KEY_SIZE,
-       .cia_setkey             =       des_setkey,
-       .cia_encrypt            =       des_encrypt,
-       .cia_decrypt            =       des_decrypt } }
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       DES_KEY_SIZE,
+                       .cia_max_keysize        =       DES_KEY_SIZE,
+                       .cia_setkey             =       des_setkey,
+                       .cia_encrypt            =       des_encrypt,
+                       .cia_decrypt            =       des_decrypt,
+                       .cia_encrypt_ecb        =       des_encrypt_ecb,
+                       .cia_decrypt_ecb        =       des_decrypt_ecb,
+                       .cia_encrypt_cbc        =       des_encrypt_cbc,
+                       .cia_decrypt_cbc        =       des_decrypt_cbc,
+               }
+       }
 };
 
 /*
@@ -107,20 +166,18 @@ static struct crypto_alg des_alg = {
  *   Implementers MUST reject keys that exhibit this property.
  *
  */
-static int
-des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen,
+                          u32 *flags)
 {
        int i, ret;
-       struct crypt_s390_des3_128_ctx *dctx;
+       struct crypt_s390_des3_128_ctx *dctx = ctx;
        const u8* temp_key = key;
 
-       dctx = ctx;
        if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) {
-
                *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
                return -EINVAL;
        }
-       for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
+       for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
                ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
                if (ret < 0)
                        return ret;
@@ -129,24 +186,85 @@ des3_128_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
        return 0;
 }
 
-static void
-des3_128_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_128_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
-       struct crypt_s390_des3_128_ctx *dctx;
+       struct crypt_s390_des3_128_ctx *dctx = ctx;
 
-       dctx = ctx;
        crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
-                       DES3_128_BLOCK_SIZE);
+                     DES3_128_BLOCK_SIZE);
 }
 
-static void
-des3_128_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_128_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
-       struct crypt_s390_des3_128_ctx *dctx;
+       struct crypt_s390_des3_128_ctx *dctx = ctx;
 
-       dctx = ctx;
        crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
-                       DES3_128_BLOCK_SIZE);
+                     DES3_128_BLOCK_SIZE);
+}
+
+static unsigned int des3_128_encrypt_ecb(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+       ret = crypt_s390_km(KM_TDEA_128_ENCRYPT, sctx->key, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
+}
+
+static unsigned int des3_128_decrypt_ecb(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+       ret = crypt_s390_km(KM_TDEA_128_DECRYPT, sctx->key, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
+}
+
+static unsigned int des3_128_encrypt_cbc(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+
+       memcpy(sctx->iv, desc->info, DES3_128_BLOCK_SIZE);
+       ret = crypt_s390_kmc(KMC_TDEA_128_ENCRYPT, &sctx->iv, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       memcpy(desc->info, sctx->iv, DES3_128_BLOCK_SIZE);
+       return nbytes;
+}
+
+static unsigned int des3_128_decrypt_cbc(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_128_BLOCK_SIZE - 1);
+
+       memcpy(&sctx->iv, desc->info, DES3_128_BLOCK_SIZE);
+       ret = crypt_s390_kmc(KMC_TDEA_128_DECRYPT, &sctx->iv, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
 }
 
 static struct crypto_alg des3_128_alg = {
@@ -156,12 +274,19 @@ static struct crypto_alg des3_128_alg = {
        .cra_ctxsize            =       sizeof(struct crypt_s390_des3_128_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(des3_128_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       DES3_128_KEY_SIZE,
-       .cia_max_keysize        =       DES3_128_KEY_SIZE,
-       .cia_setkey             =       des3_128_setkey,
-       .cia_encrypt            =       des3_128_encrypt,
-       .cia_decrypt            =       des3_128_decrypt } }
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       DES3_128_KEY_SIZE,
+                       .cia_max_keysize        =       DES3_128_KEY_SIZE,
+                       .cia_setkey             =       des3_128_setkey,
+                       .cia_encrypt            =       des3_128_encrypt,
+                       .cia_decrypt            =       des3_128_decrypt,
+                       .cia_encrypt_ecb        =       des3_128_encrypt_ecb,
+                       .cia_decrypt_ecb        =       des3_128_decrypt_ecb,
+                       .cia_encrypt_cbc        =       des3_128_encrypt_cbc,
+                       .cia_decrypt_cbc        =       des3_128_decrypt_cbc,
+               }
+       }
 };
 
 /*
@@ -177,50 +302,108 @@ static struct crypto_alg des3_128_alg = {
  *   property.
  *
  */
-static int
-des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+static int des3_192_setkey(void *ctx, const u8 *key, unsigned int keylen,
+                          u32 *flags)
 {
        int i, ret;
-       struct crypt_s390_des3_192_ctx *dctx;
-       const u8* temp_key;
+       struct crypt_s390_des3_192_ctx *dctx = ctx;
+       const u8* temp_key = key;
 
-       dctx = ctx;
-       temp_key = key;
        if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
            memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
-                                               DES_KEY_SIZE))) {
+                  DES_KEY_SIZE))) {
 
                *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
                return -EINVAL;
        }
        for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
                ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
-               if (ret < 0){
+               if (ret < 0)
                        return ret;
-               }
        }
        memcpy(dctx->key, key, keylen);
        return 0;
 }
 
-static void
-des3_192_encrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_192_encrypt(void *ctx, u8 *dst, const u8 *src)
 {
-       struct crypt_s390_des3_192_ctx *dctx;
+       struct crypt_s390_des3_192_ctx *dctx = ctx;
 
-       dctx = ctx;
        crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
-                       DES3_192_BLOCK_SIZE);
+                     DES3_192_BLOCK_SIZE);
 }
 
-static void
-des3_192_decrypt(void *ctx, u8 *dst, const u8 *src)
+static void des3_192_decrypt(void *ctx, u8 *dst, const u8 *src)
 {
-       struct crypt_s390_des3_192_ctx *dctx;
+       struct crypt_s390_des3_192_ctx *dctx = ctx;
 
-       dctx = ctx;
        crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
-                       DES3_192_BLOCK_SIZE);
+                     DES3_192_BLOCK_SIZE);
+}
+
+static unsigned int des3_192_encrypt_ecb(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+       ret = crypt_s390_km(KM_TDEA_192_ENCRYPT, sctx->key, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
+}
+
+static unsigned int des3_192_decrypt_ecb(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+       ret = crypt_s390_km(KM_TDEA_192_DECRYPT, sctx->key, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
+}
+
+static unsigned int des3_192_encrypt_cbc(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+
+       memcpy(sctx->iv, desc->info, DES3_192_BLOCK_SIZE);
+       ret = crypt_s390_kmc(KMC_TDEA_192_ENCRYPT, &sctx->iv, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       memcpy(desc->info, sctx->iv, DES3_192_BLOCK_SIZE);
+       return nbytes;
+}
+
+static unsigned int des3_192_decrypt_cbc(const struct cipher_desc *desc,
+                                        u8 *out, const u8 *in,
+                                        unsigned int nbytes)
+{
+       struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm);
+       int ret;
+
+       /* only use complete blocks */
+       nbytes &= ~(DES3_192_BLOCK_SIZE - 1);
+
+       memcpy(&sctx->iv, desc->info, DES3_192_BLOCK_SIZE);
+       ret = crypt_s390_kmc(KMC_TDEA_192_DECRYPT, &sctx->iv, out, in, nbytes);
+       BUG_ON((ret < 0) || (ret != nbytes));
+
+       return nbytes;
 }
 
 static struct crypto_alg des3_192_alg = {
@@ -230,44 +413,43 @@ static struct crypto_alg des3_192_alg = {
        .cra_ctxsize            =       sizeof(struct crypt_s390_des3_192_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_list               =       LIST_HEAD_INIT(des3_192_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       DES3_192_KEY_SIZE,
-       .cia_max_keysize        =       DES3_192_KEY_SIZE,
-       .cia_setkey             =       des3_192_setkey,
-       .cia_encrypt            =       des3_192_encrypt,
-       .cia_decrypt            =       des3_192_decrypt } }
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       DES3_192_KEY_SIZE,
+                       .cia_max_keysize        =       DES3_192_KEY_SIZE,
+                       .cia_setkey             =       des3_192_setkey,
+                       .cia_encrypt            =       des3_192_encrypt,
+                       .cia_decrypt            =       des3_192_decrypt,
+                       .cia_encrypt_ecb        =       des3_192_encrypt_ecb,
+                       .cia_decrypt_ecb        =       des3_192_decrypt_ecb,
+                       .cia_encrypt_cbc        =       des3_192_encrypt_cbc,
+                       .cia_decrypt_cbc        =       des3_192_decrypt_cbc,
+               }
+       }
 };
 
-
-
-static int
-init(void)
+static int init(void)
 {
-       int ret;
+       int ret = 0;
 
        if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
            !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
-           !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)){
+           !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
                return -ENOSYS;
-       }
 
-       ret = 0;
-       ret |= (crypto_register_alg(&des_alg) == 0)? 0:1;
-       ret |= (crypto_register_alg(&des3_128_alg) == 0)? 0:2;
-       ret |= (crypto_register_alg(&des3_192_alg) == 0)? 0:4;
-       if (ret){
+       ret |= (crypto_register_alg(&des_alg) == 0) ? 0:1;
+       ret |= (crypto_register_alg(&des3_128_alg) == 0) ? 0:2;
+       ret |= (crypto_register_alg(&des3_192_alg) == 0) ? 0:4;
+       if (ret) {
                crypto_unregister_alg(&des3_192_alg);
                crypto_unregister_alg(&des3_128_alg);
                crypto_unregister_alg(&des_alg);
                return -EEXIST;
        }
-
-       printk(KERN_INFO "crypt_s390: des_s390 loaded.\n");
        return 0;
 }
 
-static void __exit
-fini(void)
+static void __exit fini(void)
 {
        crypto_unregister_alg(&des3_192_alg);
        crypto_unregister_alg(&des3_128_alg);
index b75bdbd476c7384c2dbc891964ee8e9c52f2b117..1ec5e92b34544a360126717d233394c524c2643f 100644 (file)
@@ -51,6 +51,7 @@ static void sha256_update(void *ctx, const u8 *data, unsigned int len)
 {
        struct s390_sha256_ctx *sctx = ctx;
        unsigned int index;
+       int ret;
 
        /* how much is already in the buffer? */
        index = sctx->count / 8 & 0x3f;
@@ -58,15 +59,29 @@ static void sha256_update(void *ctx, const u8 *data, unsigned int len)
        /* update message bit length */
        sctx->count += len * 8;
 
-       /* process one block */
-       if ((index + len) >= SHA256_BLOCK_SIZE) {
+       if ((index + len) < SHA256_BLOCK_SIZE)
+               goto store;
+
+       /* process one stored block */
+       if (index) {
                memcpy(sctx->buf + index, data, SHA256_BLOCK_SIZE - index);
-               crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf,
-                               SHA256_BLOCK_SIZE);
+               ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, sctx->buf,
+                                     SHA256_BLOCK_SIZE);
+               BUG_ON(ret != SHA256_BLOCK_SIZE);
                data += SHA256_BLOCK_SIZE - index;
                len -= SHA256_BLOCK_SIZE - index;
        }
 
+       /* process as many blocks as possible */
+       if (len >= SHA256_BLOCK_SIZE) {
+               ret = crypt_s390_kimd(KIMD_SHA_256, sctx->state, data,
+                                     len & ~(SHA256_BLOCK_SIZE - 1));
+               BUG_ON(ret != (len & ~(SHA256_BLOCK_SIZE - 1)));
+               data += ret;
+               len -= ret;
+       }
+
+store:
        /* anything left? */
        if (len)
                memcpy(sctx->buf + index , data, len);
@@ -119,9 +134,9 @@ static struct crypto_alg alg = {
        .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
        .cra_u          =       { .digest = {
        .dia_digestsize =       SHA256_DIGEST_SIZE,
-       .dia_init       =       sha256_init,
-       .dia_update     =       sha256_update,
-       .dia_final      =       sha256_final } }
+       .dia_init       =       sha256_init,
+       .dia_update     =       sha256_update,
+       .dia_final      =       sha256_final } }
 };
 
 static int init(void)
index 2ff90a1a105657afc6586fa86c5689843db66fdc..008c74526fd3344e8599e30657ad18d5e048e96b 100644 (file)
@@ -58,10 +58,18 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
  */
 unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-       struct stack_frame *sf;
+       struct stack_frame *sf, *low, *high;
 
-       sf = (struct stack_frame *) tsk->thread.ksp;
-       sf = (struct stack_frame *) sf->back_chain;
+       if (!tsk || !task_stack_page(tsk))
+               return 0;
+       low = task_stack_page(tsk);
+       high = (struct stack_frame *) task_pt_regs(tsk);
+       sf = (struct stack_frame *) (tsk->thread.ksp & PSW_ADDR_INSN);
+       if (sf <= low || sf > high)
+               return 0;
+       sf = (struct stack_frame *) (sf->back_chain & PSW_ADDR_INSN);
+       if (sf <= low || sf > high)
+               return 0;
        return sf->gprs[8];
 }
 
index b03847d100d90fde48437391ead7692bd4c0c10f..de8784267473a1c16a3922005b5ec50ece22df3d 100644 (file)
@@ -268,7 +268,7 @@ static void do_machine_restart_nonsmp(char * __unused)
        reipl_diag();
 
        if (MACHINE_IS_VM)
-               cpcmd ("IPL", NULL, 0);
+               cpcmd ("IPL", NULL, 0, NULL);
        else
                reipl (0x10000 | S390_lowcore.ipl_device);
 }
@@ -276,14 +276,14 @@ static void do_machine_restart_nonsmp(char * __unused)
 static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
+                cpcmd(vmhalt_cmd, NULL, 0, NULL);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
 static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
+                cpcmd(vmpoff_cmd, NULL, 0, NULL);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
@@ -315,6 +315,11 @@ void machine_power_off(void)
        _machine_power_off();
 }
 
+/*
+ * Dummy power off function.
+ */
+void (*pm_power_off)(void) = machine_power_off;
+
 static void __init
 add_memory_hole(unsigned long start, unsigned long end)
 {
index b0d8ca8e5eebd7917a87b88ebfae98a258fa0cc4..7c0fe152a111f394b6310a6fbd535615388372fd 100644 (file)
@@ -214,7 +214,7 @@ void account_ticks(struct pt_regs *regs)
 #endif
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-       account_user_vtime(current);
+       account_tick_vtime(current);
 #else
        while (ticks--)
                update_process_times(user_mode(regs));
index 22a895ecb7a4f2b5bbcde59377d4061f947e76b5..dfe6f08566171a8979153ea6169bcc53539d1cb3 100644 (file)
@@ -32,7 +32,7 @@ DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
  */
-void account_user_vtime(struct task_struct *tsk)
+void account_tick_vtime(struct task_struct *tsk)
 {
        cputime_t cputime;
        __u64 timer, clock;
@@ -72,6 +72,31 @@ void account_user_vtime(struct task_struct *tsk)
        run_posix_cpu_timers(tsk);
 }
 
+/*
+ * Update process times based on virtual cpu times stored by entry.S
+ * to the lowcore fields user_timer, system_timer & steal_clock.
+ */
+void account_vtime(struct task_struct *tsk)
+{
+       cputime_t cputime;
+       __u64 timer;
+
+       timer = S390_lowcore.last_update_timer;
+       asm volatile ("  STPT %0"    /* Store current cpu timer value */
+                     : "=m" (S390_lowcore.last_update_timer) );
+       S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
+
+       cputime = S390_lowcore.user_timer >> 12;
+       S390_lowcore.user_timer -= cputime << 12;
+       S390_lowcore.steal_clock -= cputime << 12;
+       account_user_time(tsk, cputime);
+
+       cputime =  S390_lowcore.system_timer >> 12;
+       S390_lowcore.system_timer -= cputime << 12;
+       S390_lowcore.steal_clock -= cputime << 12;
+       account_system_time(tsk, 0, cputime);
+}
+
 /*
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
index d9b97b3c597f2eb90e694ba385f3f61814c54c35..f20b51ff1d86ee24b9c65a098781d58d0c688387 100644 (file)
@@ -4,5 +4,6 @@
 
 EXTRA_AFLAGS := -traditional
 
-lib-y += delay.o string.o spinlock.o
+lib-y += delay.o string.o
 lib-y += $(if $(CONFIG_64BIT),uaccess64.o,uaccess.o)
+lib-$(CONFIG_SMP) += spinlock.o
\ No newline at end of file
index 68d79c50208172cfdaea271ab61f335099749b5f..60f80a4eed4e52cfc99756738024738a42537237 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 
-atomic_t spin_retry_counter;
 int spin_retry = 1000;
 
 /**
@@ -45,7 +44,6 @@ _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
                        _diag44();
                        count = spin_retry;
                }
-               atomic_inc(&spin_retry_counter);
                if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
                        return;
        }
@@ -58,7 +56,6 @@ _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
        int count = spin_retry;
 
        while (count-- > 0) {
-               atomic_inc(&spin_retry_counter);
                if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
                        return 1;
        }
@@ -77,7 +74,6 @@ _raw_read_lock_wait(raw_rwlock_t *rw)
                        _diag44();
                        count = spin_retry;
                }
-               atomic_inc(&spin_retry_counter);
                old = rw->lock & 0x7fffffffU;
                if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
                        return;
@@ -92,7 +88,6 @@ _raw_read_trylock_retry(raw_rwlock_t *rw)
        int count = spin_retry;
 
        while (count-- > 0) {
-               atomic_inc(&spin_retry_counter);
                old = rw->lock & 0x7fffffffU;
                if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
                        return 1;
@@ -111,7 +106,6 @@ _raw_write_lock_wait(raw_rwlock_t *rw)
                        _diag44();
                        count = spin_retry;
                }
-               atomic_inc(&spin_retry_counter);
                if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
                        return;
        }
@@ -124,7 +118,6 @@ _raw_write_trylock_retry(raw_rwlock_t *rw)
        int count = spin_retry;
 
        while (count-- > 0) {
-               atomic_inc(&spin_retry_counter);
                if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
                        return 1;
        }
index d4fee2a7937306db8010a07e48d05c63ef697fad..3278d234bb1b26ba9d2eeb1c3927cbfb17dae900 100644 (file)
@@ -53,21 +53,6 @@ static int sh_bus_resume(struct device *dev)
        return 0;
 }
 
-static struct device sh_bus_devices[SH_NR_BUSES] = {
-       {
-               .bus_id         = SH_BUS_NAME_VIRT,
-       },
-};
-
-struct bus_type sh_bus_types[SH_NR_BUSES] = {
-       {
-               .name           = SH_BUS_NAME_VIRT,
-               .match          = sh_bus_match,
-               .suspend        = sh_bus_suspend,
-               .resume         = sh_bus_resume,
-       },
-};
-
 static int sh_device_probe(struct device *dev)
 {
        struct sh_dev *shdev = to_sh_dev(dev);
@@ -90,6 +75,23 @@ static int sh_device_remove(struct device *dev)
        return 0;
 }
 
+static struct device sh_bus_devices[SH_NR_BUSES] = {
+       {
+               .bus_id         = SH_BUS_NAME_VIRT,
+       },
+};
+
+struct bus_type sh_bus_types[SH_NR_BUSES] = {
+       {
+               .name           = SH_BUS_NAME_VIRT,
+               .match          = sh_bus_match,
+               .probe          = sh_bus_probe,
+               .remove         = sh_bus_remove,
+               .suspend        = sh_bus_suspend,
+               .resume         = sh_bus_resume,
+       },
+};
+
 int sh_device_register(struct sh_dev *dev)
 {
        if (!dev)
@@ -133,8 +135,6 @@ int sh_driver_register(struct sh_driver *drv)
                return -EINVAL;
        }
 
-       drv->drv.probe  = sh_device_probe;
-       drv->drv.remove = sh_device_remove;
        drv->drv.bus    = &sh_bus_types[drv->bus_id];
 
        return driver_register(&drv->drv);
index 322972fd064eac3d45f363c4dd87f56da500d406..45435ff589c17e8252008431e3ee659dedc08ed8 100644 (file)
@@ -67,7 +67,8 @@ USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
 # in CFLAGS.  Otherwise, it would cause ld to complain about the two different
 # errnos.
 
-CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask
+CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
+       -Dmktime=kernel_mktime
 CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
 
 include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
index f1ed83f3f083761cd80d04d65a83f8da40afd484..db57546a709d96b77e7dbc8987fc2c61ec40cf80 100644 (file)
@@ -38,34 +38,100 @@ static inline int major_to_index(int major)
        return major % MAX_PROBE_HASH;
 }
 
-#ifdef CONFIG_PROC_FS
-/* get block device names in somewhat random order */
-int get_blkdev_list(char *p, int used)
+struct blkdev_info {
+        int index;
+        struct blk_major_name *bd;
+};
+
+/*
+ * iterate over a list of blkdev_info structures.  allows
+ * the major_names array to be iterated over from outside this file
+ * must be called with the block_subsys_sem held
+ */
+void *get_next_blkdev(void *dev)
+{
+        struct blkdev_info *info;
+
+        if (dev == NULL) {
+                info = kmalloc(sizeof(*info), GFP_KERNEL);
+                if (!info)
+                        goto out;
+                info->index=0;
+                info->bd = major_names[info->index];
+                if (info->bd)
+                        goto out;
+        } else {
+                info = dev;
+        }
+
+        while (info->index < ARRAY_SIZE(major_names)) {
+                if (info->bd)
+                        info->bd = info->bd->next;
+                if (info->bd)
+                        goto out;
+                /*
+                 * No devices on this chain, move to the next
+                 */
+                info->index++;
+                info->bd = (info->index < ARRAY_SIZE(major_names)) ?
+                       major_names[info->index] : NULL;
+                if (info->bd)
+                        goto out;
+        }
+
+out:
+        return info;
+}
+
+void *acquire_blkdev_list(void)
+{
+        down(&block_subsys_sem);
+        return get_next_blkdev(NULL);
+}
+
+void release_blkdev_list(void *dev)
+{
+        up(&block_subsys_sem);
+        kfree(dev);
+}
+
+
+/*
+ * Count the number of records in the blkdev_list.
+ * must be called with the block_subsys_sem held
+ */
+int count_blkdev_list(void)
 {
        struct blk_major_name *n;
-       int i, len;
+       int i, count;
 
-       len = snprintf(p, (PAGE_SIZE-used), "\nBlock devices:\n");
+       count = 0;
 
-       down(&block_subsys_sem);
        for (i = 0; i < ARRAY_SIZE(major_names); i++) {
-               for (n = major_names[i]; n; n = n->next) {
-                       /*
-                        * If the curent string plus the 5 extra characters
-                        * in the line would run us off the page, then we're done
-                        */
-                       if ((len + used + strlen(n->name) + 5) >= PAGE_SIZE)
-                               goto page_full;
-                       len += sprintf(p+len, "%3d %s\n",
-                                      n->major, n->name);
-               }
+               for (n = major_names[i]; n; n = n->next)
+                               count++;
        }
-page_full:
-       up(&block_subsys_sem);
 
-       return len;
+       return count;
 }
-#endif
+
+/*
+ * extract the major and name values from a blkdev_info struct
+ * passed in as a void to *dev.  Must be called with
+ * block_subsys_sem held
+ */
+int get_blkdev_info(void *dev, int *major, char **name)
+{
+        struct blkdev_info *info = dev;
+
+        if (info->bd == NULL)
+                return 1;
+
+        *major = info->bd->major;
+        *name = info->bd->name;
+        return 0;
+}
+
 
 int register_blkdev(unsigned int major, const char *name)
 {
index 48f446d3c671ade5a5198384c729f83118a35033..283c089537bcd3799226a2e87bfb43a5b62fdc31 100644 (file)
@@ -44,6 +44,8 @@ source "drivers/char/Kconfig"
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/spi/Kconfig"
+
 source "drivers/w1/Kconfig"
 
 source "drivers/hwmon/Kconfig"
index 7fc3f0f08b29e76aa8db89f82e6e62378391d61d..7c45050ecd03c1b25d883429820875823a797bf4 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_FUSION)          += message/
 obj-$(CONFIG_IEEE1394)         += ieee1394/
 obj-y                          += cdrom/
 obj-$(CONFIG_MTD)              += mtd/
+obj-$(CONFIG_SPI)              += spi/
 obj-$(CONFIG_PCCARD)           += pcmcia/
 obj-$(CONFIG_DIO)              += dio/
 obj-$(CONFIG_SBUS)             += sbus/
index 7e1a445955bc1fd5a747038a4b2b1e867cf42b08..3758b558d2b5e9ad1b2905049ea090874f63876a 100644 (file)
@@ -153,7 +153,7 @@ static int acpi_ec_polling_mode = EC_POLLING;
                              Transaction Management
    -------------------------------------------------------------------------- */
 
-static inline u32 acpi_ec_read_status(union acpi_ec *ec)
+static u32 acpi_ec_read_status(union acpi_ec *ec)
 {
        u32 status = 0;
 
index 2b905016664d9779439c4fa047507256b0cb2faf..730a9ce0a14a44d45c45fe34b15f1277157fe1d2 100644 (file)
@@ -78,7 +78,13 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
        pr_debug("%s: Matched Device %s with Driver %s\n",
                 drv->bus->name, dev->bus_id, drv->name);
        dev->driver = drv;
-       if (drv->probe) {
+       if (dev->bus->probe) {
+               ret = dev->bus->probe(dev);
+               if (ret) {
+                       dev->driver = NULL;
+                       goto ProbeFailed;
+               }
+       } else if (drv->probe) {
                ret = drv->probe(dev);
                if (ret) {
                        dev->driver = NULL;
@@ -203,7 +209,9 @@ static void __device_release_driver(struct device * dev)
                sysfs_remove_link(&dev->kobj, "driver");
                klist_remove(&dev->knode_driver);
 
-               if (drv->remove)
+               if (dev->bus->remove)
+                       dev->bus->remove(dev);
+               else if (drv->remove)
                        drv->remove(dev);
                dev->driver = NULL;
                put_driver(drv);
index 161f3a390d90651973a8a738446b3b7330950a09..b400314e1c62d46d9d2dc047cb76a08292b7f9ff 100644 (file)
@@ -171,6 +171,11 @@ static void klist_devices_put(struct klist_node *n)
  */
 int driver_register(struct device_driver * drv)
 {
+       if ((drv->bus->probe && drv->probe) ||
+           (drv->bus->remove && drv->remove) ||
+           (drv->bus->shutdown && drv->shutdown)) {
+               printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
+       }
        klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);
        init_completion(&drv->unloaded);
        return bus_add_driver(drv);
index 3d384e3d34decfa481fe2ed722e2e4b9445a41d6..e97e911ebf7a0374117245f18910f496319c53a9 100644 (file)
@@ -48,7 +48,7 @@ struct firmware_priv {
        struct timer_list timeout;
 };
 
-static inline void
+static void
 fw_load_abort(struct firmware_priv *fw_priv)
 {
        set_bit(FW_STATUS_ABORT, &fw_priv->status);
index 0f81731bdfa8122aeccfc439907533cfd3fc98ba..461554a025172d329b714e9bc46a389991eabe28 100644 (file)
@@ -327,7 +327,7 @@ EXPORT_SYMBOL_GPL(platform_device_register);
  *     @pdev:  platform device we're unregistering
  *
  *     Unregistration is done in 2 steps. Fisrt we release all resources
- *     and remove it from the sybsystem, then we drop reference count by
+ *     and remove it from the subsystem, then we drop reference count by
  *     calling platform_device_put().
  */
 void platform_device_unregister(struct platform_device * pdev)
index f50a08be424b1c524122b19ba769342f38caf02b..c2475f3134eae05e8d625af83a79afb210d07712 100644 (file)
@@ -35,12 +35,15 @@ extern int sysdev_shutdown(void);
  */
 void device_shutdown(void)
 {
-       struct device * dev;
+       struct device * dev, *devn;
 
        down_write(&devices_subsys.rwsem);
-       list_for_each_entry_reverse(dev, &devices_subsys.kset.list,
+       list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
                                kobj.entry) {
-               if (dev->driver && dev->driver->shutdown) {
+               if (dev->bus && dev->bus->shutdown) {
+                       dev_dbg(dev, "shutdown\n");
+                       dev->bus->shutdown(dev);
+               } else if (dev->driver && dev->driver->shutdown) {
                        dev_dbg(dev, "shutdown\n");
                        dev->driver->shutdown(dev);
                }
index 864729046e22ac4dbe9e39efc30131bf5f8e4216..5f6d1a5cce11fc3bebdf1f0ab29c875db7850e09 100644 (file)
@@ -294,7 +294,7 @@ fail:
  * This helper just factors out common code between do_lo_send_direct_write()
  * and do_lo_send_write().
  */
-static inline int __do_lo_send_write(struct file *file,
+static int __do_lo_send_write(struct file *file,
                u8 __user *buf, const int len, loff_t pos)
 {
        ssize_t bw;
index 51b7a5c5b77ab2bd5e5584cc96f72af11d016d96..93affeeef7bd3675009f1edc885684824bad633f 100644 (file)
@@ -247,7 +247,7 @@ static inline struct pkt_rb_node *pkt_rbtree_next(struct pkt_rb_node *node)
        return rb_entry(n, struct pkt_rb_node, rb_node);
 }
 
-static inline void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
+static void pkt_rbtree_erase(struct pktcdvd_device *pd, struct pkt_rb_node *node)
 {
        rb_erase(&node->rb_node, &pd->bio_queue);
        mempool_free(node, pd->rb_pool);
@@ -315,7 +315,7 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod
 /*
  * Add a bio to a single linked list defined by its head and tail pointers.
  */
-static inline void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
+static void pkt_add_list_last(struct bio *bio, struct bio **list_head, struct bio **list_tail)
 {
        bio->bi_next = NULL;
        if (*list_tail) {
index 8fddfdfd0fbdcca1c779cc12736051f8c9439c6c..7bd4ef90411542f6996596ae0f36d9a0880d22de 100644 (file)
@@ -494,7 +494,7 @@ static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char
        }
 }
 
-static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
+static void bcsp_complete_rx_pkt(struct hci_uart *hu)
 {
        struct bcsp_struct *bcsp = hu->priv;
        int pass_up;
index 667a21c72edbdf40df19183c64501e25efc83fa1..7ac365b5d9ece1af03bbcaae6438282e0a7c7706 100644 (file)
@@ -129,7 +129,6 @@ static struct serial_state rs_table[1];
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 #include <asm/uaccess.h>
 
index caeecc2c36dab290ddd6da3cf85c38bab7c2d157..a080cdd6081ed639baa377107982e3246dc9a7c9 100644 (file)
@@ -220,7 +220,7 @@ static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv)
        ADVANCE_RING();
 }
 
-static __inline__ void r128_emit_state(drm_r128_private_t * dev_priv)
+static void r128_emit_state(drm_r128_private_t * dev_priv)
 {
        drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
        unsigned int dirty = sarea_priv->dirty;
index e469f641c7289b75439b06e8f31e402eba7cf44c..dd5dc8fa490de04820743c9c15435b1cc4da1224 100644 (file)
@@ -160,7 +160,6 @@ static void rs_wait_until_sent(struct tty_struct *, int);
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct esp_struct *info,
                                        char *name, const char *routine)
index 204a7302a4a9597e13fcfda676d53f00cb7a79af..e38a5f0e07bbd7d90cc843e9b5d171d622335f20 100644 (file)
@@ -34,7 +34,6 @@
 #define DEBUG 
 
 static char *                  tmp_buf; 
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static int gs_debug;
 
index 050e70ee59202f03ff3bee326583d5de4530f534..119e629656b7b4d5e835ec1fe11a423a4f35c258 100644 (file)
@@ -82,7 +82,6 @@
 static struct riscom_board * IRQ_to_board[16];
 static struct tty_driver *riscom_driver;
 static unsigned char * tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static unsigned long baud_table[] =  {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
index f36342ae8e7e91b7121162580d13f39faa176deb..037c940ac71b8bb10b4dd2788aff141980ddba63 100644 (file)
@@ -129,7 +129,6 @@ struct cyclades_port cy_port[] = {
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf = 0;
-DECLARE_MUTEX(tmp_buf_sem);
 
 /*
  * This is used to look up the divisor speeds and the timeouts
index 0a574bdbce3695df8ab4e0553753e9e5f2f7a1f7..5343e9fc6ab7e721dc1a578e6a6e81e044549490 100644 (file)
@@ -184,7 +184,6 @@ static int sx_poll = HZ;
 
 static struct tty_driver *specialix_driver;
 static unsigned char * tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static unsigned long baud_table[] =  {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
@@ -2556,8 +2555,6 @@ static int __init specialix_init_module(void)
 
        func_enter();
 
-       init_MUTEX(&tmp_buf_sem); /* Init de the semaphore - pvdl */
-
        if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {
                for(i = 0; i < SX_NBOARD; i++) {
                        sx_board[i].base = iobase[i];
index 9f1b466c4f84fcd555c79f92021ce17343c936de..ede688a4e141ad71834fb90930d83b7466751caa 100644 (file)
@@ -951,7 +951,6 @@ static void* mgsl_get_text_ptr(void)
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int mgsl_paranoia_check(struct mgsl_struct *info,
                                        char *name, const char *routine)
index a6544790af60bc358bce4e6a9c80704de8ec03de..c0dfcf273f0a5bd84e3be9dcd4f4a22835dcd198 100644 (file)
@@ -395,12 +395,38 @@ config MACHZ_WDT
          To compile this driver as a module, choose M here: the
          module will be called machzwd.
 
+config SBC_EPX_C3_WATCHDOG
+       tristate "Winsystems SBC EPX-C3 watchdog"
+       depends on WATCHDOG && X86
+       ---help---
+         This is the driver for the built-in watchdog timer on the EPX-C3
+         Single-board computer made by Winsystems, Inc.
+
+         *Note*: This hardware watchdog is not probeable and thus there
+         is no way to know if writing to its IO address will corrupt
+         your system or have any real effect.  The only way to be sure
+         that this driver does what you want is to make sure you
+         are runnning it on an EPX-C3 from Winsystems with the watchdog
+         timer at IO address 0x1ee and 0x1ef.  It will write to both those
+         IO ports.  Basically, the assumption is made that if you compile
+         this driver into your kernel and/or load it as a module, that you
+         know what you are doing and that you are in fact running on an
+         EPX-C3 board!
+
+         To compile this driver as a module, choose M here: the
+         module will be called sbc_epx_c3.
+
+
 # PowerPC Architecture
 
 config 8xx_WDT
        tristate "MPC8xx Watchdog Timer"
        depends on WATCHDOG && 8xx
 
+config 83xx_WDT
+       tristate "MPC83xx Watchdog Timer"
+       depends on WATCHDOG && PPC_83xx
+
 config MV64X60_WDT
        tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
        depends on WATCHDOG && MV64X60
index cfd0a39877102224f901856f805562ed4feb1b33..36c0b282b8ba30d3119325acd5fb844a65d1aa7f 100644 (file)
@@ -52,9 +52,11 @@ obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
+obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 
 # PowerPC Architecture
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
 obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
 obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
 
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
new file mode 100644 (file)
index 0000000..5d6f506
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * mpc83xx_wdt.c - MPC83xx watchdog userspace interface
+ *
+ * Authors: Dave Updegraff <dave@cray.org>
+ *         Kumar Gala <galak@kernel.crashing.org>
+ *             Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
+ *                             ..and from sc520_wdt
+ *
+ * Note: it appears that you can only actually ENABLE or DISABLE the thing
+ * once after POR. Once enabled, you cannot disable, and vice versa.
+ *
+ * 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/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+struct mpc83xx_wdt {
+       __be32 res0;
+       __be32 swcrr; /* System watchdog control register */
+#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
+#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
+#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
+#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
+       __be32 swcnr; /* System watchdog count register */
+       u8 res1[2];
+       __be16 swsrr; /* System watchdog service register */
+       u8 res2[0xF0];
+};
+
+static struct mpc83xx_wdt __iomem *wd_base;
+
+static u16 timeout = 0xffff;
+module_param(timeout, ushort, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535");
+
+static int reset = 1;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
+
+/*
+ * We always prescale, but if someone really doesn't want to they can set this
+ * to 0
+ */
+static int prescale = 1;
+static unsigned int timeout_sec;
+
+static unsigned long wdt_is_open;
+static spinlock_t wdt_spinlock;
+
+static void mpc83xx_wdt_keepalive(void)
+{
+       /* Ping the WDT */
+       spin_lock(&wdt_spinlock);
+       out_be16(&wd_base->swsrr, 0x556c);
+       out_be16(&wd_base->swsrr, 0xaa39);
+       spin_unlock(&wdt_spinlock);
+}
+
+static ssize_t mpc83xx_wdt_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       if (count)
+               mpc83xx_wdt_keepalive();
+       return count;
+}
+
+static int mpc83xx_wdt_open(struct inode *inode, struct file *file)
+{
+       u32 tmp = SWCRR_SWEN;
+       if (test_and_set_bit(0, &wdt_is_open))
+               return -EBUSY;
+
+       /* Once we start the watchdog we can't stop it */
+       __module_get(THIS_MODULE);
+
+       /* Good, fire up the show */
+       if (prescale)
+               tmp |= SWCRR_SWPR;
+       if (reset)
+               tmp |= SWCRR_SWRI;
+
+       tmp |= timeout << 16;
+
+       out_be32(&wd_base->swcrr, tmp);
+
+       return nonseekable_open(inode, file);
+}
+
+static int mpc83xx_wdt_release(struct inode *inode, struct file *file)
+{
+       printk(KERN_CRIT "Unexpected close, not stopping watchdog!\n");
+       mpc83xx_wdt_keepalive();
+       clear_bit(0, &wdt_is_open);
+       return 0;
+}
+
+static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
+                               unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       static struct watchdog_info ident = {
+               .options = WDIOF_KEEPALIVEPING,
+               .firmware_version = 1,
+               .identity = "MPC83xx",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+       case WDIOC_KEEPALIVE:
+               mpc83xx_wdt_keepalive();
+               return 0;
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout_sec, p);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static struct file_operations mpc83xx_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = mpc83xx_wdt_write,
+       .ioctl          = mpc83xx_wdt_ioctl,
+       .open           = mpc83xx_wdt_open,
+       .release        = mpc83xx_wdt_release,
+};
+
+static struct miscdevice mpc83xx_wdt_miscdev = {
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &mpc83xx_wdt_fops,
+};
+
+static int __devinit mpc83xx_wdt_probe(struct platform_device *dev)
+{
+       struct resource *r;
+       int ret;
+       unsigned int *freq = dev->dev.platform_data;
+
+       /* get a pointer to the register memory */
+       r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+       if (!r) {
+               ret = -ENODEV;
+               goto err_out;
+       }
+
+       wd_base = ioremap(r->start, sizeof (struct mpc83xx_wdt));
+
+       if (wd_base == NULL) {
+               ret = -ENOMEM;
+               goto err_out;
+       }
+
+       ret = misc_register(&mpc83xx_wdt_miscdev);
+       if (ret) {
+               printk(KERN_ERR "cannot register miscdev on minor=%d "
+                               "(err=%d)\n",
+                               WATCHDOG_MINOR, ret);
+               goto err_unmap;
+       }
+
+       /* Calculate the timeout in seconds */
+       if (prescale)
+               timeout_sec = (timeout * 0x10000) / (*freq);
+       else
+               timeout_sec = timeout / (*freq);
+
+       printk(KERN_INFO "WDT driver for MPC83xx initialized. "
+               "mode:%s timeout=%d (%d seconds)\n",
+               reset ? "reset":"interrupt", timeout, timeout_sec);
+
+       spin_lock_init(&wdt_spinlock);
+
+       return 0;
+
+err_unmap:
+       iounmap(wd_base);
+err_out:
+       return ret;
+}
+
+static int __devexit mpc83xx_wdt_remove(struct platform_device *dev)
+{
+       misc_deregister(&mpc83xx_wdt_miscdev);
+       iounmap(wd_base);
+
+       return 0;
+}
+
+static struct platform_driver mpc83xx_wdt_driver = {
+       .probe          = mpc83xx_wdt_probe,
+       .remove         = __devexit_p(mpc83xx_wdt_remove),
+       .driver         = {
+               .name   = "mpc83xx_wdt",
+       },
+};
+
+static int __init mpc83xx_wdt_init(void)
+{
+       return platform_driver_register(&mpc83xx_wdt_driver);
+}
+
+static void __exit mpc83xx_wdt_exit(void)
+{
+       platform_driver_unregister(&mpc83xx_wdt_driver);
+}
+
+module_init(mpc83xx_wdt_init);
+module_exit(mpc83xx_wdt_exit);
+
+MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
+MODULE_DESCRIPTION("Driver for watchdog timer in MPC83xx uProcessor");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index fb88b4041dca4730ab70def4f462b97bead64ed1..b474ea52d6e8554446f524f0067de44e6881ed7d 100644 (file)
@@ -74,7 +74,7 @@ static int sa1100dog_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
 {
        if (len)
                /* Refresh OSMR3 timer. */
@@ -96,20 +96,20 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
 
        switch (cmd) {
        case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+               ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
                                   sizeof(ident)) ? -EFAULT : 0;
                break;
 
        case WDIOC_GETSTATUS:
-               ret = put_user(0, (int *)arg);
+               ret = put_user(0, (int __user *)arg);
                break;
 
        case WDIOC_GETBOOTSTATUS:
-               ret = put_user(boot_status, (int *)arg);
+               ret = put_user(boot_status, (int __user *)arg);
                break;
 
        case WDIOC_SETTIMEOUT:
-               ret = get_user(time, (int *)arg);
+               ret = get_user(time, (int __user *)arg);
                if (ret)
                        break;
 
@@ -123,7 +123,7 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
                /*fall through*/
 
        case WDIOC_GETTIMEOUT:
-               ret = put_user(pre_margin / OSCR_FREQ, (int *)arg);
+               ret = put_user(pre_margin / OSCR_FREQ, (int __user *)arg);
                break;
 
        case WDIOC_KEEPALIVE:
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
new file mode 100644 (file)
index 0000000..9517646
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *     SBC EPX C3 0.1  A Hardware Watchdog Device for the Winsystems EPX-C3
+ *     single board computer
+ *
+ *     (c) Copyright 2006 Calin A. Culianu <calin@ajvar.org>, 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.
+ *
+ *     based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define PFX "epx_c3: "
+static int epx_c3_alive;
+
+#define WATCHDOG_TIMEOUT 1             /* 1 sec default timeout */
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+#define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */
+#define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */
+
+static void epx_c3_start(void)
+{
+       outb(1, EPXC3_WATCHDOG_CTL_REG);
+}
+
+static void epx_c3_stop(void)
+{
+
+       outb(0, EPXC3_WATCHDOG_CTL_REG);
+
+       printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void epx_c3_pet(void)
+{
+       outb(1, EPXC3_WATCHDOG_PET_REG);
+}
+
+/*
+ *     Allow only one person to hold it open
+ */
+static int epx_c3_open(struct inode *inode, struct file *file)
+{
+       if (epx_c3_alive)
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       /* Activate timer */
+       epx_c3_start();
+       epx_c3_pet();
+
+       epx_c3_alive = 1;
+       printk(KERN_INFO "Started watchdog timer.\n");
+
+       return nonseekable_open(inode, file);
+}
+
+static int epx_c3_release(struct inode *inode, struct file *file)
+{
+       /* Shut off the timer.
+        * Lock it in if it's a module and we defined ...NOWAYOUT */
+       if (!nowayout)
+               epx_c3_stop();          /* Turn the WDT off */
+
+       epx_c3_alive = 0;
+
+       return 0;
+}
+
+static ssize_t epx_c3_write(struct file *file, const char *data,
+                       size_t len, loff_t *ppos)
+{
+       /* Refresh the timer. */
+       if (len)
+               epx_c3_pet();
+       return len;
+}
+
+static int epx_c3_ioctl(struct inode *inode, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       int options, retval = -EINVAL;
+       static struct watchdog_info ident = {
+               .options                = WDIOF_KEEPALIVEPING |
+                                         WDIOF_MAGICCLOSE,
+               .firmware_version       = 0,
+               .identity               = "Winsystems EPX-C3 H/W Watchdog",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user((struct watchdog_info *)arg,
+                                &ident, sizeof(ident)))
+                       return -EFAULT;
+               return 0;
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0,(int *)arg);
+       case WDIOC_KEEPALIVE:
+               epx_c3_pet();
+               return 0;
+       case WDIOC_GETTIMEOUT:
+               return put_user(WATCHDOG_TIMEOUT,(int *)arg);
+       case WDIOC_SETOPTIONS: {
+               if (get_user(options, (int *)arg))
+                       return -EFAULT;
+
+               if (options & WDIOS_DISABLECARD) {
+                       epx_c3_stop();
+                       retval = 0;
+               }
+
+               if (options & WDIOS_ENABLECARD) {
+                       epx_c3_start();
+                       retval = 0;
+               }
+
+               return retval;
+       }
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code,
+                               void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               epx_c3_stop();          /* Turn the WDT off */
+
+       return NOTIFY_DONE;
+}
+
+static struct file_operations epx_c3_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = epx_c3_write,
+       .ioctl          = epx_c3_ioctl,
+       .open           = epx_c3_open,
+       .release        = epx_c3_release,
+};
+
+static struct miscdevice epx_c3_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &epx_c3_fops,
+};
+
+static struct notifier_block epx_c3_notifier = {
+       .notifier_call = epx_c3_notify_sys,
+};
+
+static const char banner[] __initdata =
+    KERN_INFO PFX "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
+
+static int __init watchdog_init(void)
+{
+       int ret;
+
+       ret = register_reboot_notifier(&epx_c3_notifier);
+       if (ret) {
+               printk(KERN_ERR PFX "cannot register reboot notifier "
+                       "(err=%d)\n", ret);
+               return ret;
+       }
+
+       ret = misc_register(&epx_c3_miscdev);
+       if (ret) {
+               printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
+                       "(err=%d)\n", WATCHDOG_MINOR, ret);
+               unregister_reboot_notifier(&epx_c3_notifier);
+               return ret;
+       }
+
+       printk(banner);
+
+       return 0;
+}
+
+static void __exit watchdog_exit(void)
+{
+       misc_deregister(&epx_c3_miscdev);
+       unregister_reboot_notifier(&epx_c3_notifier);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>");
+MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC.  Note that there is no way to probe for this device -- so only use it if you are *sure* you are runnning on this specific SBC system from Winsystems!  It writes to IO ports 0x1ee and 0x1ef!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index a9163d02983af68f069887a520330e84470cc58b..277a843a87a60bc3cc001fe10529d7c053e8a7f5 100644 (file)
@@ -41,7 +41,6 @@ static DEFINE_SPINLOCK(cpufreq_driver_lock);
 /* internal prototypes */
 static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
 static void handle_update(void *data);
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
 
 /**
  * Two notifier lists: the "policy" list is involved in the 
@@ -127,7 +126,7 @@ static unsigned int debug_ratelimit = 1;
 static unsigned int disable_ratelimit = 1;
 static DEFINE_SPINLOCK(disable_ratelimit_lock);
 
-static inline void cpufreq_debug_enable_ratelimit(void)
+static void cpufreq_debug_enable_ratelimit(void)
 {
        unsigned long flags;
 
@@ -137,7 +136,7 @@ static inline void cpufreq_debug_enable_ratelimit(void)
        spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
 }
 
-static inline void cpufreq_debug_disable_ratelimit(void)
+static void cpufreq_debug_disable_ratelimit(void)
 {
        unsigned long flags;
 
@@ -206,7 +205,7 @@ static inline void cpufreq_debug_disable_ratelimit(void) { return; }
 static unsigned long l_p_j_ref;
 static unsigned int  l_p_j_ref_freq;
 
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
+static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
 {
        if (ci->flags & CPUFREQ_CONST_LOOPS)
                return;
index ffe6f44ac76fcb080e976584c7499f1ace73e13d..ca8e69d2f64d632118c32e9c05c63a5ae660a71e 100644 (file)
@@ -83,7 +83,6 @@ int dio_register_driver(struct dio_driver *drv)
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &dio_bus_type;
-       drv->driver.probe = dio_device_probe;
 
        /* register with core */
        count = driver_register(&drv->driver);
@@ -145,7 +144,8 @@ static int dio_bus_match(struct device *dev, struct device_driver *drv)
 
 struct bus_type dio_bus_type = {
        .name   = "dio",
-       .match  = dio_bus_match
+       .match  = dio_bus_match,
+       .probe  = dio_device_probe,
 };
 
 
index dfedb777d8c90e607a88ce37fbd8846a6934a7c9..fdb8b042e64d121f3e4a9be60719efc25cf17f0c 100644 (file)
@@ -49,7 +49,7 @@
 MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
 MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("3.1");
+MODULE_VERSION("3.2");
 
 #define BIOS_SCAN_LIMIT 0xffffffff
 #define MAX_IMAGE_LENGTH 16
@@ -564,12 +564,10 @@ static ssize_t read_rbu_data(struct kobject *kobj, char *buffer,
 
 static void callbackfn_rbu(const struct firmware *fw, void *context)
 {
-       int rc = 0;
+       rbu_data.entry_created = 0;
 
-       if (!fw || !fw->size) {
-               rbu_data.entry_created = 0;
+       if (!fw || !fw->size)
                return;
-       }
 
        spin_lock(&rbu_data.lock);
        if (!strcmp(image_type, "mono")) {
@@ -592,15 +590,6 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
        } else
                pr_debug("invalid image type specified.\n");
        spin_unlock(&rbu_data.lock);
-
-       rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
-               "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu);
-       if (rc)
-               printk(KERN_ERR
-                       "dell_rbu:%s request_firmware_nowait failed"
-                       " %d\n", __FUNCTION__, rc);
-       else
-               rbu_data.entry_created = 1;
 }
 
 static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
@@ -735,14 +724,7 @@ static int __init dcdrbu_init(void)
        sysfs_create_bin_file(&rbu_device->dev.kobj,
                &rbu_packet_size_attr);
 
-       rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
-               "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu);
-       if (rc)
-               printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait"
-                       " failed %d\n", __FUNCTION__, rc);
-       else
-               rbu_data.entry_created = 1;
-
+       rbu_data.entry_created = 0;
        return rc;
 
 }
index 52b77477df573232730bbdae37ccd61d53beba22..0ce58b506046b458edb85cf7bda4472a56920da1 100644 (file)
@@ -63,13 +63,6 @@ static int i2c_bus_resume(struct device * dev)
        return rc;
 }
 
-struct bus_type i2c_bus_type = {
-       .name =         "i2c",
-       .match =        i2c_device_match,
-       .suspend =      i2c_bus_suspend,
-       .resume =       i2c_bus_resume,
-};
-
 static int i2c_device_probe(struct device *dev)
 {
        return -ENODEV;
@@ -80,6 +73,15 @@ static int i2c_device_remove(struct device *dev)
        return 0;
 }
 
+struct bus_type i2c_bus_type = {
+       .name =         "i2c",
+       .match =        i2c_device_match,
+       .probe =        i2c_device_probe,
+       .remove =       i2c_device_remove,
+       .suspend =      i2c_bus_suspend,
+       .resume =       i2c_bus_resume,
+};
+
 void i2c_adapter_dev_release(struct device *dev)
 {
        struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
@@ -90,8 +92,6 @@ struct device_driver i2c_adapter_driver = {
        .owner = THIS_MODULE,
        .name = "i2c_adapter",
        .bus = &i2c_bus_type,
-       .probe = i2c_device_probe,
-       .remove = i2c_device_remove,
 };
 
 static void i2c_adapter_class_dev_release(struct class_device *dev)
@@ -294,8 +294,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
        /* add the driver to the list of i2c drivers in the driver core */
        driver->driver.owner = owner;
        driver->driver.bus = &i2c_bus_type;
-       driver->driver.probe = i2c_device_probe;
-       driver->driver.remove = i2c_device_remove;
 
        res = driver_register(&driver->driver);
        if (res)
index 9b2ebd219ad0d0fc8c8aabf83c60fc1b99548d1f..3325660f7248561b3b490d971581dc0b8033e1cd 100644 (file)
@@ -980,7 +980,7 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
  * and attempt to recover if there are problems.  Returns  0 if everything's
  * ok; nonzero if the request has been terminated.
  */
-static inline
+static
 int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
 {
        if (ireason == 2)
@@ -1539,7 +1539,7 @@ int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
 /*
  * Write handling
  */
-static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
+static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason)
 {
        /* Two notes about IDE interrupt reason here - 0 means that
         * the drive wants to receive data from us, 2 means that
@@ -3256,9 +3256,8 @@ sector_t ide_cdrom_capacity (ide_drive_t *drive)
 }
 #endif
 
-static int ide_cd_remove(struct device *dev)
+static void ide_cd_remove(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        struct cdrom_info *info = drive->driver_data;
 
        ide_unregister_subdriver(drive, info->driver);
@@ -3266,8 +3265,6 @@ static int ide_cd_remove(struct device *dev)
        del_gendisk(info->disk);
 
        ide_cd_put(info);
-
-       return 0;
 }
 
 static void ide_cd_release(struct kref *kref)
@@ -3291,7 +3288,7 @@ static void ide_cd_release(struct kref *kref)
        kfree(info);
 }
 
-static int ide_cd_probe(struct device *);
+static int ide_cd_probe(ide_drive_t *);
 
 #ifdef CONFIG_PROC_FS
 static int proc_idecd_read_capacity
@@ -3317,9 +3314,9 @@ static ide_driver_t ide_cdrom_driver = {
                .owner          = THIS_MODULE,
                .name           = "ide-cdrom",
                .bus            = &ide_bus_type,
-               .probe          = ide_cd_probe,
-               .remove         = ide_cd_remove,
        },
+       .probe                  = ide_cd_probe,
+       .remove                 = ide_cd_remove,
        .version                = IDECD_VERSION,
        .media                  = ide_cdrom,
        .supports_dsc_overlap   = 1,
@@ -3413,9 +3410,8 @@ static char *ignore = NULL;
 module_param(ignore, charp, 0400);
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-static int ide_cd_probe(struct device *dev)
+static int ide_cd_probe(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        struct cdrom_info *info;
        struct gendisk *g;
        struct request_sense sense;
index cab362ea03360a1bc4586ebec338cf2cadf74418..ca25f9e3d0f4e6816f6155d0cd00f79dd07509d1 100644 (file)
@@ -477,7 +477,7 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id)
               && id->lba_capacity_2;
 }
 
-static inline void idedisk_check_hpa(ide_drive_t *drive)
+static void idedisk_check_hpa(ide_drive_t *drive)
 {
        unsigned long long capacity, set_max;
        int lba48 = idedisk_supports_lba48(drive->id);
@@ -997,9 +997,8 @@ static void ide_cacheflush_p(ide_drive_t *drive)
                printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
 }
 
-static int ide_disk_remove(struct device *dev)
+static void ide_disk_remove(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        struct ide_disk_obj *idkp = drive->driver_data;
        struct gendisk *g = idkp->disk;
 
@@ -1010,8 +1009,6 @@ static int ide_disk_remove(struct device *dev)
        ide_cacheflush_p(drive);
 
        ide_disk_put(idkp);
-
-       return 0;
 }
 
 static void ide_disk_release(struct kref *kref)
@@ -1027,12 +1024,10 @@ static void ide_disk_release(struct kref *kref)
        kfree(idkp);
 }
 
-static int ide_disk_probe(struct device *dev);
+static int ide_disk_probe(ide_drive_t *drive);
 
-static void ide_device_shutdown(struct device *dev)
+static void ide_device_shutdown(ide_drive_t *drive)
 {
-       ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
-
 #ifdef CONFIG_ALPHA
        /* On Alpha, halt(8) doesn't actually turn the machine off,
           it puts you into the sort of firmware monitor. Typically,
@@ -1054,7 +1049,7 @@ static void ide_device_shutdown(struct device *dev)
        }
 
        printk("Shutdown: %s\n", drive->name);
-       dev->bus->suspend(dev, PMSG_SUSPEND);
+       drive->gendev.bus->suspend(&drive->gendev, PMSG_SUSPEND);
 }
 
 static ide_driver_t idedisk_driver = {
@@ -1062,10 +1057,10 @@ static ide_driver_t idedisk_driver = {
                .owner          = THIS_MODULE,
                .name           = "ide-disk",
                .bus            = &ide_bus_type,
-               .probe          = ide_disk_probe,
-               .remove         = ide_disk_remove,
-               .shutdown       = ide_device_shutdown,
        },
+       .probe                  = ide_disk_probe,
+       .remove                 = ide_disk_remove,
+       .shutdown               = ide_device_shutdown,
        .version                = IDEDISK_VERSION,
        .media                  = ide_disk,
        .supports_dsc_overlap   = 0,
@@ -1182,9 +1177,8 @@ static struct block_device_operations idedisk_ops = {
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-static int ide_disk_probe(struct device *dev)
+static int ide_disk_probe(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        struct ide_disk_obj *idkp;
        struct gendisk *g;
 
index 5945f551aaaad493d22c05e358f2df30b06f110c..1f8db9ac05d12def5a5fe8f49a7492e628e4a0bb 100644 (file)
@@ -1871,9 +1871,8 @@ static void idefloppy_setup (ide_drive_t *drive, idefloppy_floppy_t *floppy)
        idefloppy_add_settings(drive);
 }
 
-static int ide_floppy_remove(struct device *dev)
+static void ide_floppy_remove(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        idefloppy_floppy_t *floppy = drive->driver_data;
        struct gendisk *g = floppy->disk;
 
@@ -1882,8 +1881,6 @@ static int ide_floppy_remove(struct device *dev)
        del_gendisk(g);
 
        ide_floppy_put(floppy);
-
-       return 0;
 }
 
 static void ide_floppy_release(struct kref *kref)
@@ -1922,16 +1919,16 @@ static ide_proc_entry_t idefloppy_proc[] = {
 
 #endif /* CONFIG_PROC_FS */
 
-static int ide_floppy_probe(struct device *);
+static int ide_floppy_probe(ide_drive_t *);
 
 static ide_driver_t idefloppy_driver = {
        .gen_driver = {
                .owner          = THIS_MODULE,
                .name           = "ide-floppy",
                .bus            = &ide_bus_type,
-               .probe          = ide_floppy_probe,
-               .remove         = ide_floppy_remove,
        },
+       .probe                  = ide_floppy_probe,
+       .remove                 = ide_floppy_remove,
        .version                = IDEFLOPPY_VERSION,
        .media                  = ide_floppy,
        .supports_dsc_overlap   = 0,
@@ -2136,9 +2133,8 @@ static struct block_device_operations idefloppy_ops = {
        .revalidate_disk= idefloppy_revalidate_disk
 };
 
-static int ide_floppy_probe(struct device *dev)
+static int ide_floppy_probe(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        idefloppy_floppy_t *floppy;
        struct gendisk *g;
 
index fab9b2b025044728e5d80a53d929e7d9715ba36a..0101d0def7c519814f45c09af92221a27c9362fb 100644 (file)
@@ -4682,9 +4682,8 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor)
        idetape_add_settings(drive);
 }
 
-static int ide_tape_remove(struct device *dev)
+static void ide_tape_remove(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        idetape_tape_t *tape = drive->driver_data;
 
        ide_unregister_subdriver(drive, tape->driver);
@@ -4692,8 +4691,6 @@ static int ide_tape_remove(struct device *dev)
        ide_unregister_region(tape->disk);
 
        ide_tape_put(tape);
-
-       return 0;
 }
 
 static void ide_tape_release(struct kref *kref)
@@ -4745,16 +4742,16 @@ static ide_proc_entry_t idetape_proc[] = {
 
 #endif
 
-static int ide_tape_probe(struct device *);
+static int ide_tape_probe(ide_drive_t *);
 
 static ide_driver_t idetape_driver = {
        .gen_driver = {
                .owner          = THIS_MODULE,
                .name           = "ide-tape",
                .bus            = &ide_bus_type,
-               .probe          = ide_tape_probe,
-               .remove         = ide_tape_remove,
        },
+       .probe                  = ide_tape_probe,
+       .remove                 = ide_tape_remove,
        .version                = IDETAPE_VERSION,
        .media                  = ide_tape,
        .supports_dsc_overlap   = 1,
@@ -4825,9 +4822,8 @@ static struct block_device_operations idetape_block_ops = {
        .ioctl          = idetape_ioctl,
 };
 
-static int ide_tape_probe(struct device *dev)
+static int ide_tape_probe(ide_drive_t *drive)
 {
-       ide_drive_t *drive = to_ide_device(dev);
        idetape_tape_t *tape;
        struct gendisk *g;
        int minor;
@@ -4883,9 +4879,9 @@ static int ide_tape_probe(struct device *dev)
        idetape_setup(drive, tape, minor);
 
        class_device_create(idetape_sysfs_class, NULL,
-                       MKDEV(IDETAPE_MAJOR, minor), dev, "%s", tape->name);
+                       MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name);
        class_device_create(idetape_sysfs_class, NULL,
-                       MKDEV(IDETAPE_MAJOR, minor + 128), dev, "n%s", tape->name);
+                       MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
 
        devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
                        S_IFCHR | S_IRUGO | S_IWUGO,
index 62ebefd6394a0af83b10a188c86e9a12a4d1520a..9834dce4e20fa93715c62f63f8d457eed6510ce5 100644 (file)
@@ -308,7 +308,7 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
                ide_pio_sector(drive, write);
 }
 
-static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
                                     unsigned int write)
 {
        if (rq->bio)    /* fs request */
index ec5a4cb173b073ff41f5a41608e73c6fcd343817..afeb02bbb72210b4ee45bbcf6c6ed5e4a0cd416c 100644 (file)
@@ -1949,10 +1949,41 @@ static int ide_uevent(struct device *dev, char **envp, int num_envp,
        return 0;
 }
 
+static int generic_ide_probe(struct device *dev)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       ide_driver_t *drv = to_ide_driver(dev->driver);
+
+       return drv->probe ? drv->probe(drive) : -ENODEV;
+}
+
+static int generic_ide_remove(struct device *dev)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       ide_driver_t *drv = to_ide_driver(dev->driver);
+
+       if (drv->remove)
+               drv->remove(drive);
+
+       return 0;
+}
+
+static void generic_ide_shutdown(struct device *dev)
+{
+       ide_drive_t *drive = to_ide_device(dev);
+       ide_driver_t *drv = to_ide_driver(dev->driver);
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(drive);
+}
+
 struct bus_type ide_bus_type = {
        .name           = "ide",
        .match          = ide_bus_match,
        .uevent         = ide_uevent,
+       .probe          = generic_ide_probe,
+       .remove         = generic_ide_remove,
+       .shutdown       = generic_ide_shutdown,
        .dev_attrs      = ide_dev_attrs,
        .suspend        = generic_ide_suspend,
        .resume         = generic_ide_resume,
index 3a611fe5497e06c0b9e2de2cc9eaf75d2abf0caa..2514de3480d83bf10fdd84a67e0a81172e10efab 100644 (file)
@@ -856,7 +856,7 @@ static void cm_format_req(struct cm_req_msg *req_msg,
                       param->private_data_len);
 }
 
-static inline int cm_validate_req_param(struct ib_cm_req_param *param)
+static int cm_validate_req_param(struct ib_cm_req_param *param)
 {
        /* peer-to-peer not supported */
        if (param->peer_to_peer)
@@ -1005,7 +1005,7 @@ static inline int cm_is_active_peer(__be64 local_ca_guid, __be64 remote_ca_guid,
                 (be32_to_cpu(local_qpn) > be32_to_cpu(remote_qpn))));
 }
 
-static inline void cm_format_paths_from_req(struct cm_req_msg *req_msg,
+static void cm_format_paths_from_req(struct cm_req_msg *req_msg,
                                            struct ib_sa_path_rec *primary_path,
                                            struct ib_sa_path_rec *alt_path)
 {
@@ -3163,22 +3163,6 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-static __be64 cm_get_ca_guid(struct ib_device *device)
-{
-       struct ib_device_attr *device_attr;
-       __be64 guid;
-       int ret;
-
-       device_attr = kmalloc(sizeof *device_attr, GFP_KERNEL);
-       if (!device_attr)
-               return 0;
-
-       ret = ib_query_device(device, device_attr);
-       guid = ret ? 0 : device_attr->node_guid;
-       kfree(device_attr);
-       return guid;
-}
-
 static void cm_add_one(struct ib_device *device)
 {
        struct cm_device *cm_dev;
@@ -3200,9 +3184,7 @@ static void cm_add_one(struct ib_device *device)
                return;
 
        cm_dev->device = device;
-       cm_dev->ca_guid = cm_get_ca_guid(device);
-       if (!cm_dev->ca_guid)
-               goto error1;
+       cm_dev->ca_guid = device->node_guid;
 
        set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
        for (i = 1; i <= device->phys_port_cnt; i++) {
@@ -3217,11 +3199,11 @@ static void cm_add_one(struct ib_device *device)
                                                        cm_recv_handler,
                                                        port);
                if (IS_ERR(port->mad_agent))
-                       goto error2;
+                       goto error1;
 
                ret = ib_modify_port(device, i, 0, &port_modify);
                if (ret)
-                       goto error3;
+                       goto error2;
        }
        ib_set_client_data(device, &cm_client, cm_dev);
 
@@ -3230,9 +3212,9 @@ static void cm_add_one(struct ib_device *device)
        write_unlock_irqrestore(&cm.device_lock, flags);
        return;
 
-error3:
-       ib_unregister_mad_agent(port->mad_agent);
 error2:
+       ib_unregister_mad_agent(port->mad_agent);
+error1:
        port_modify.set_port_cap_mask = 0;
        port_modify.clr_port_cap_mask = IB_PORT_CM_SUP;
        while (--i) {
@@ -3240,7 +3222,6 @@ error2:
                ib_modify_port(device, port->port_num, 0, &port_modify);
                ib_unregister_mad_agent(port->mad_agent);
        }
-error1:
        kfree(cm_dev);
 }
 
index e169e798354b6283174a66adfe0f0027b9412ca5..b2f3cb91d9bcfdb90159d1e72cc5493d6798343d 100644 (file)
@@ -38,8 +38,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "core_priv.h"
 
@@ -57,13 +56,13 @@ static LIST_HEAD(device_list);
 static LIST_HEAD(client_list);
 
 /*
- * device_sem protects access to both device_list and client_list.
+ * device_mutex protects access to both device_list and client_list.
  * There's no real point to using multiple locks or something fancier
  * like an rwsem: we always access both lists, and we're always
  * modifying one list or the other list.  In any case this is not a
  * hot path so there's no point in trying to optimize.
  */
-static DECLARE_MUTEX(device_sem);
+static DEFINE_MUTEX(device_mutex);
 
 static int ib_device_check_mandatory(struct ib_device *device)
 {
@@ -221,7 +220,7 @@ int ib_register_device(struct ib_device *device)
 {
        int ret;
 
-       down(&device_sem);
+       mutex_lock(&device_mutex);
 
        if (strchr(device->name, '%')) {
                ret = alloc_name(device->name);
@@ -259,7 +258,7 @@ int ib_register_device(struct ib_device *device)
        }
 
  out:
-       up(&device_sem);
+       mutex_unlock(&device_mutex);
        return ret;
 }
 EXPORT_SYMBOL(ib_register_device);
@@ -276,7 +275,7 @@ void ib_unregister_device(struct ib_device *device)
        struct ib_client_data *context, *tmp;
        unsigned long flags;
 
-       down(&device_sem);
+       mutex_lock(&device_mutex);
 
        list_for_each_entry_reverse(client, &client_list, list)
                if (client->remove)
@@ -284,7 +283,7 @@ void ib_unregister_device(struct ib_device *device)
 
        list_del(&device->core_list);
 
-       up(&device_sem);
+       mutex_unlock(&device_mutex);
 
        spin_lock_irqsave(&device->client_data_lock, flags);
        list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
@@ -312,14 +311,14 @@ int ib_register_client(struct ib_client *client)
 {
        struct ib_device *device;
 
-       down(&device_sem);
+       mutex_lock(&device_mutex);
 
        list_add_tail(&client->list, &client_list);
        list_for_each_entry(device, &device_list, core_list)
                if (client->add && !add_client_context(device, client))
                        client->add(device);
 
-       up(&device_sem);
+       mutex_unlock(&device_mutex);
 
        return 0;
 }
@@ -339,7 +338,7 @@ void ib_unregister_client(struct ib_client *client)
        struct ib_device *device;
        unsigned long flags;
 
-       down(&device_sem);
+       mutex_lock(&device_mutex);
 
        list_for_each_entry(device, &device_list, core_list) {
                if (client->remove)
@@ -355,7 +354,7 @@ void ib_unregister_client(struct ib_client *client)
        }
        list_del(&client->list);
 
-       up(&device_sem);
+       mutex_unlock(&device_mutex);
 }
 EXPORT_SYMBOL(ib_unregister_client);
 
index 1f1743c5c9a3b0ead51a349ac445e682f8d9b866..5982d687a0009e2db11befcce2d0c4d9fde519f8 100644 (file)
@@ -445,13 +445,7 @@ static int ib_device_uevent(struct class_device *cdev, char **envp,
                return -ENOMEM;
 
        /*
-        * It might be nice to pass the node GUID with the event, but
-        * right now the only way to get it is to query the device
-        * provider, and this can crash during device removal because
-        * we are will be running after driver removal has started.
-        * We could add a node_guid field to struct ib_device, or we
-        * could just let userspace read the node GUID from sysfs when
-        * devices are added.
+        * It would be nice to pass the node GUID with the event...
         */
 
        envp[i] = NULL;
@@ -623,21 +617,15 @@ static ssize_t show_sys_image_guid(struct class_device *cdev, char *buf)
 static ssize_t show_node_guid(struct class_device *cdev, char *buf)
 {
        struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
-       struct ib_device_attr attr;
-       ssize_t ret;
 
        if (!ibdev_is_alive(dev))
                return -ENODEV;
 
-       ret = ib_query_device(dev, &attr);
-       if (ret)
-               return ret;
-
        return sprintf(buf, "%04x:%04x:%04x:%04x\n",
-                      be16_to_cpu(((__be16 *) &attr.node_guid)[0]),
-                      be16_to_cpu(((__be16 *) &attr.node_guid)[1]),
-                      be16_to_cpu(((__be16 *) &attr.node_guid)[2]),
-                      be16_to_cpu(((__be16 *) &attr.node_guid)[3]));
+                      be16_to_cpu(((__be16 *) &dev->node_guid)[0]),
+                      be16_to_cpu(((__be16 *) &dev->node_guid)[1]),
+                      be16_to_cpu(((__be16 *) &dev->node_guid)[2]),
+                      be16_to_cpu(((__be16 *) &dev->node_guid)[3]));
 }
 
 static CLASS_DEVICE_ATTR(node_type, S_IRUGO, show_node_type, NULL);
index 6e15787d1de1a1d32e6f0df8a2e95c02e79a12f4..e95c4293a4967d108ea79c7c1d5166bbaad00999 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/mount.h>
 #include <linux/cdev.h>
 #include <linux/idr.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 
@@ -113,7 +114,7 @@ static struct ib_client ucm_client = {
        .remove = ib_ucm_remove_one
 };
 
-static DECLARE_MUTEX(ctx_id_mutex);
+static DEFINE_MUTEX(ctx_id_mutex);
 static DEFINE_IDR(ctx_id_table);
 static DECLARE_BITMAP(dev_map, IB_UCM_MAX_DEVICES);
 
@@ -121,7 +122,7 @@ static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id)
 {
        struct ib_ucm_context *ctx;
 
-       down(&ctx_id_mutex);
+       mutex_lock(&ctx_id_mutex);
        ctx = idr_find(&ctx_id_table, id);
        if (!ctx)
                ctx = ERR_PTR(-ENOENT);
@@ -129,7 +130,7 @@ static struct ib_ucm_context *ib_ucm_ctx_get(struct ib_ucm_file *file, int id)
                ctx = ERR_PTR(-EINVAL);
        else
                atomic_inc(&ctx->ref);
-       up(&ctx_id_mutex);
+       mutex_unlock(&ctx_id_mutex);
 
        return ctx;
 }
@@ -186,9 +187,9 @@ static struct ib_ucm_context *ib_ucm_ctx_alloc(struct ib_ucm_file *file)
                if (!result)
                        goto error;
 
-               down(&ctx_id_mutex);
+               mutex_lock(&ctx_id_mutex);
                result = idr_get_new(&ctx_id_table, ctx, &ctx->id);
-               up(&ctx_id_mutex);
+               mutex_unlock(&ctx_id_mutex);
        } while (result == -EAGAIN);
 
        if (result)
@@ -550,9 +551,9 @@ static ssize_t ib_ucm_create_id(struct ib_ucm_file *file,
 err2:
        ib_destroy_cm_id(ctx->cm_id);
 err1:
-       down(&ctx_id_mutex);
+       mutex_lock(&ctx_id_mutex);
        idr_remove(&ctx_id_table, ctx->id);
-       up(&ctx_id_mutex);
+       mutex_unlock(&ctx_id_mutex);
        kfree(ctx);
        return result;
 }
@@ -572,7 +573,7 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       down(&ctx_id_mutex);
+       mutex_lock(&ctx_id_mutex);
        ctx = idr_find(&ctx_id_table, cmd.id);
        if (!ctx)
                ctx = ERR_PTR(-ENOENT);
@@ -580,7 +581,7 @@ static ssize_t ib_ucm_destroy_id(struct ib_ucm_file *file,
                ctx = ERR_PTR(-EINVAL);
        else
                idr_remove(&ctx_id_table, ctx->id);
-       up(&ctx_id_mutex);
+       mutex_unlock(&ctx_id_mutex);
 
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
@@ -1280,9 +1281,9 @@ static int ib_ucm_close(struct inode *inode, struct file *filp)
                                 struct ib_ucm_context, file_list);
                up(&file->mutex);
 
-               down(&ctx_id_mutex);
+               mutex_lock(&ctx_id_mutex);
                idr_remove(&ctx_id_table, ctx->id);
-               up(&ctx_id_mutex);
+               mutex_unlock(&ctx_id_mutex);
 
                ib_destroy_cm_id(ctx->cm_id);
                ib_ucm_cleanup_events(ctx);
index 7114e3fbab00d2d1bfccd76c7964ad6d4a81c130..f7eecbc6af6c2b0b371ff361508d9ae074cab484 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <linux/kref.h>
 #include <linux/idr.h>
+#include <linux/mutex.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
@@ -88,7 +89,7 @@ struct ib_uverbs_event_file {
 
 struct ib_uverbs_file {
        struct kref                             ref;
-       struct semaphore                        mutex;
+       struct mutex                            mutex;
        struct ib_uverbs_device                *device;
        struct ib_ucontext                     *ucontext;
        struct ib_event_handler                 event_handler;
@@ -131,7 +132,7 @@ struct ib_ucq_object {
        u32                     async_events_reported;
 };
 
-extern struct semaphore ib_uverbs_idr_mutex;
+extern struct mutex ib_uverbs_idr_mutex;
 extern struct idr ib_uverbs_pd_idr;
 extern struct idr ib_uverbs_mr_idr;
 extern struct idr ib_uverbs_mw_idr;
index a02c5a05c984f7931310de1fca427265efc3e05b..407b6284d7d5c502c88595f1f2820bf856aac1c8 100644 (file)
@@ -67,7 +67,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
 
        if (file->ucontext) {
                ret = -EINVAL;
@@ -119,7 +119,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
 
        fd_install(resp.async_fd, filp);
 
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        return in_len;
 
@@ -131,7 +131,7 @@ err_free:
        ibdev->dealloc_ucontext(ucontext);
 
 err:
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
        return ret;
 }
 
@@ -157,7 +157,7 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
        memset(&resp, 0, sizeof resp);
 
        resp.fw_ver                    = attr.fw_ver;
-       resp.node_guid                 = attr.node_guid;
+       resp.node_guid                 = file->device->ib_dev->node_guid;
        resp.sys_image_guid            = attr.sys_image_guid;
        resp.max_mr_size               = attr.max_mr_size;
        resp.page_size_cap             = attr.page_size_cap;
@@ -290,7 +290,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
        pd->uobject = uobj;
        atomic_set(&pd->usecnt, 0);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
 retry:
        if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
@@ -314,11 +314,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->list, &file->ucontext->pd_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -326,7 +326,7 @@ err_idr:
        idr_remove(&ib_uverbs_pd_idr, uobj->id);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        ib_dealloc_pd(pd);
 
 err:
@@ -346,7 +346,7 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        if (!pd || pd->uobject->context != file->ucontext)
@@ -360,14 +360,14 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        kfree(uobj);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -426,7 +426,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
 
        obj->umem.virt_base = cmd.hca_va;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        if (!pd || pd->uobject->context != file->ucontext) {
@@ -476,11 +476,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -492,7 +492,7 @@ err_unreg:
        atomic_dec(&pd->usecnt);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        ib_umem_release(file->device->ib_dev, &obj->umem);
 
@@ -513,7 +513,7 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
        if (!mr || mr->uobject->context != file->ucontext)
@@ -527,15 +527,15 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&memobj->uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_umem_release(file->device->ib_dev, &memobj->umem);
        kfree(memobj);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -628,7 +628,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
        cq->cq_context    = ev_file;
        atomic_set(&cq->usecnt, 0);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
 retry:
        if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
@@ -653,11 +653,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -665,7 +665,7 @@ err_idr:
        idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        ib_destroy_cq(cq);
 
 err:
@@ -701,7 +701,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                goto out_wc;
        }
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
        cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
        if (!cq || cq->uobject->context != file->ucontext) {
                ret = -EINVAL;
@@ -731,7 +731,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        kfree(resp);
 
 out_wc:
@@ -750,14 +750,14 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
        cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
        if (cq && cq->uobject->context == file->ucontext) {
                ib_req_notify_cq(cq, cmd.solicited_only ?
                                        IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
                ret = in_len;
        }
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret;
 }
@@ -779,7 +779,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 
        memset(&resp, 0, sizeof resp);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
        if (!cq || cq->uobject->context != file->ucontext)
@@ -795,9 +795,9 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_uverbs_release_ucq(file, ev_file, uobj);
 
@@ -811,7 +811,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -845,7 +845,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
        if (!uobj)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
@@ -930,11 +930,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -950,7 +950,7 @@ err_destroy:
                atomic_dec(&attr.srq->usecnt);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        kfree(uobj);
        return ret;
@@ -972,7 +972,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        if (!attr)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext) {
@@ -1033,7 +1033,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
        ret = in_len;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
        kfree(attr);
 
        return ret;
@@ -1054,7 +1054,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 
        memset(&resp, 0, sizeof resp);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1073,9 +1073,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->uevent.uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_uverbs_release_uevent(file, &uobj->uevent);
 
@@ -1088,7 +1088,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1119,7 +1119,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
        if (!user_wr)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1224,7 +1224,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        while (wr) {
                next = wr->next;
@@ -1341,7 +1341,7 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
        if (IS_ERR(wr))
                return PTR_ERR(wr);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1362,7 +1362,7 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        while (wr) {
                next = wr->next;
@@ -1392,7 +1392,7 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
        if (IS_ERR(wr))
                return PTR_ERR(wr);
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
        if (!srq || srq->uobject->context != file->ucontext)
@@ -1413,7 +1413,7 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        while (wr) {
                next = wr->next;
@@ -1446,7 +1446,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
        if (!uobj)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
        if (!pd || pd->uobject->context != file->ucontext) {
@@ -1498,11 +1498,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->list, &file->ucontext->ah_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -1513,7 +1513,7 @@ err_destroy:
        ib_destroy_ah(ah);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        kfree(uobj);
        return ret;
@@ -1530,7 +1530,7 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        ah = idr_find(&ib_uverbs_ah_idr, cmd.ah_handle);
        if (!ah || ah->uobject->context != file->ucontext)
@@ -1544,14 +1544,14 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_ah_idr, cmd.ah_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        kfree(uobj);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1569,7 +1569,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1602,7 +1602,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
                kfree(mcast);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1620,7 +1620,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
        if (!qp || qp->uobject->context != file->ucontext)
@@ -1641,7 +1641,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
                }
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1673,7 +1673,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
        if (!uobj)
                return -ENOMEM;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        pd  = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
 
@@ -1730,11 +1730,11 @@ retry:
                goto err_idr;
        }
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return in_len;
 
@@ -1746,7 +1746,7 @@ err_destroy:
        atomic_dec(&pd->usecnt);
 
 err_up:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        kfree(uobj);
        return ret;
@@ -1764,7 +1764,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle);
        if (!srq || srq->uobject->context != file->ucontext) {
@@ -1778,7 +1778,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
        ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
@@ -1796,7 +1796,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
        if (copy_from_user(&cmd, buf, sizeof cmd))
                return -EFAULT;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        memset(&resp, 0, sizeof resp);
 
@@ -1812,9 +1812,9 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
 
        idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle);
 
-       down(&file->mutex);
+       mutex_lock(&file->mutex);
        list_del(&uobj->uobject.list);
-       up(&file->mutex);
+       mutex_unlock(&file->mutex);
 
        ib_uverbs_release_uevent(file, uobj);
 
@@ -1827,7 +1827,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file,
                ret = -EFAULT;
 
 out:
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return ret ? ret : in_len;
 }
index 81737bd6faea1405ef9f3fe41f4f2f136e6b043c..96ea79b63df7221747e1ccd65cf1622d93dc6885 100644 (file)
@@ -66,7 +66,7 @@ enum {
 
 static struct class *uverbs_class;
 
-DECLARE_MUTEX(ib_uverbs_idr_mutex);
+DEFINE_MUTEX(ib_uverbs_idr_mutex);
 DEFINE_IDR(ib_uverbs_pd_idr);
 DEFINE_IDR(ib_uverbs_mr_idr);
 DEFINE_IDR(ib_uverbs_mw_idr);
@@ -180,7 +180,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
        if (!context)
                return 0;
 
-       down(&ib_uverbs_idr_mutex);
+       mutex_lock(&ib_uverbs_idr_mutex);
 
        list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
                struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id);
@@ -250,7 +250,7 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
                kfree(uobj);
        }
 
-       up(&ib_uverbs_idr_mutex);
+       mutex_unlock(&ib_uverbs_idr_mutex);
 
        return context->device->dealloc_ucontext(context);
 }
@@ -653,7 +653,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
        file->ucontext   = NULL;
        file->async_file = NULL;
        kref_init(&file->ref);
-       init_MUTEX(&file->mutex);
+       mutex_init(&file->mutex);
 
        filp->private_data = file;
 
index 22fdc446f25cdcd0d3100cd20dd800d7b7d42830..a14eed08a0fcb5a4503ee59695671ae8e32ac82b 100644 (file)
@@ -163,6 +163,11 @@ int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah)
        return 0;
 }
 
+int mthca_ah_grh_present(struct mthca_ah *ah)
+{
+       return !!(ah->av->g_slid & 0x80);
+}
+
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                  struct ib_ud_header *header)
 {
@@ -172,8 +177,7 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
        header->lrh.service_level   = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
        header->lrh.destination_lid = ah->av->dlid;
        header->lrh.source_lid      = cpu_to_be16(ah->av->g_slid & 0x7f);
-       if (ah->av->g_slid & 0x80) {
-               header->grh_present = 1;
+       if (mthca_ah_grh_present(ah)) {
                header->grh.traffic_class =
                        (be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 20) & 0xff;
                header->grh.flow_label    =
@@ -184,8 +188,6 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                                  &header->grh.source_gid);
                memcpy(header->grh.destination_gid.raw,
                       ah->av->dgid, 16);
-       } else {
-               header->grh_present = 0;
        }
 
        return 0;
index 22ac72bc20c388860df359ade45c8842d6fbc0e5..be1791be627bcdd08b03ac7290741f8ae133e26b 100644 (file)
@@ -606,7 +606,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
                        err = -EINVAL;
                        goto out;
                }
-               for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i) {
+               for (i = 0; i < mthca_icm_size(&iter) >> lg; ++i) {
                        if (virt != -1) {
                                pages[nent * 2] = cpu_to_be64(virt);
                                virt += 1 << lg;
@@ -727,8 +727,8 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
                 * system pages needed.
                 */
                dev->fw.arbel.fw_pages =
-                       (dev->fw.arbel.fw_pages + (1 << (PAGE_SHIFT - 12)) - 1) >>
-                       (PAGE_SHIFT - 12);
+                       ALIGN(dev->fw.arbel.fw_pages, PAGE_SIZE >> 12) >>
+                               (PAGE_SHIFT - 12);
 
                mthca_dbg(dev, "Clear int @ %llx, EQ arm @ %llx, EQ set CI @ %llx\n",
                          (unsigned long long) dev->fw.arbel.clr_int_base,
@@ -1445,6 +1445,7 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
         * pages needed.
         */
        *aux_pages = (*aux_pages + (1 << (PAGE_SHIFT - 12)) - 1) >> (PAGE_SHIFT - 12);
+       *aux_pages = ALIGN(*aux_pages, PAGE_SIZE >> 12) >> (PAGE_SHIFT - 12);
 
        return 0;
 }
index 795b379260bfeb6eb5cc77c023b0bf103c5210fd..a104ab041ea35477f0682a74c13f14d9eb61e2f5 100644 (file)
@@ -520,6 +520,7 @@ int mthca_create_ah(struct mthca_dev *dev,
 int mthca_destroy_ah(struct mthca_dev *dev, struct mthca_ah *ah);
 int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah,
                  struct ib_ud_header *header);
+int mthca_ah_grh_present(struct mthca_ah *ah);
 
 int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
 int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
index e8a948f087c06835cacf604c34188ce785ec02b7..2eabb27804cd367b138d2b0e167617a6df20d3b4 100644 (file)
@@ -45,6 +45,7 @@
 enum {
        MTHCA_NUM_ASYNC_EQE = 0x80,
        MTHCA_NUM_CMD_EQE   = 0x80,
+       MTHCA_NUM_SPARE_EQE = 0x80,
        MTHCA_EQ_ENTRY_SIZE = 0x20
 };
 
@@ -277,11 +278,10 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
 {
        struct mthca_eqe *eqe;
        int disarm_cqn;
-       int  eqes_found = 0;
+       int eqes_found = 0;
+       int set_ci = 0;
 
        while ((eqe = next_eqe_sw(eq))) {
-               int set_ci = 0;
-
                /*
                 * Make sure we read EQ entry contents after we've
                 * checked the ownership bit.
@@ -345,12 +345,6 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
                                        be16_to_cpu(eqe->event.cmd.token),
                                        eqe->event.cmd.status,
                                        be64_to_cpu(eqe->event.cmd.out_param));
-                       /*
-                        * cmd_event() may add more commands.
-                        * The card will think the queue has overflowed if
-                        * we don't tell it we've been processing events.
-                        */
-                       set_ci = 1;
                        break;
 
                case MTHCA_EVENT_TYPE_PORT_CHANGE:
@@ -385,8 +379,16 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
                set_eqe_hw(eqe);
                ++eq->cons_index;
                eqes_found = 1;
+               ++set_ci;
 
-               if (unlikely(set_ci)) {
+               /*
+                * The HCA will think the queue has overflowed if we
+                * don't tell it we've been processing events.  We
+                * create our EQs with MTHCA_NUM_SPARE_EQE extra
+                * entries, so we must update our consumer index at
+                * least that often.
+                */
+               if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) {
                        /*
                         * Conditional on hca_type is OK here because
                         * this is a rare case, not the fast path.
@@ -862,19 +864,19 @@ int __devinit mthca_init_eq_table(struct mthca_dev *dev)
        intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ?
                128 : dev->eq_table.inta_pin;
 
-       err = mthca_create_eq(dev, dev->limits.num_cqs,
+       err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
                              (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
                              &dev->eq_table.eq[MTHCA_EQ_COMP]);
        if (err)
                goto err_out_unmap;
 
-       err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE,
+       err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE,
                              (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,
                              &dev->eq_table.eq[MTHCA_EQ_ASYNC]);
        if (err)
                goto err_out_comp;
 
-       err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE,
+       err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE,
                              (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr,
                              &dev->eq_table.eq[MTHCA_EQ_CMD]);
        if (err)
index 4cc7e2846df16c08e4f114a7832ca86b066b8cdb..484a7e6b7f8c895de887e8d3cfdbdfb4345390ee 100644 (file)
@@ -33,7 +33,7 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *
- * $Id: mthca_provider.c 1397 2004-12-28 05:09:00Z roland $
+ * $Id: mthca_provider.c 4859 2006-01-09 21:55:10Z roland $
  */
 
 #include <rdma/ib_smi.h>
 #include "mthca_user.h"
 #include "mthca_memfree.h"
 
+static void init_query_mad(struct ib_smp *mad)
+{
+       mad->base_version  = 1;
+       mad->mgmt_class    = IB_MGMT_CLASS_SUBN_LID_ROUTED;
+       mad->class_version = 1;
+       mad->method        = IB_MGMT_METHOD_GET;
+}
+
 static int mthca_query_device(struct ib_device *ibdev,
                              struct ib_device_attr *props)
 {
@@ -55,7 +63,7 @@ static int mthca_query_device(struct ib_device *ibdev,
 
        u8 status;
 
-       in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
        out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
        if (!in_mad || !out_mad)
                goto out;
@@ -64,12 +72,8 @@ static int mthca_query_device(struct ib_device *ibdev,
 
        props->fw_ver              = mdev->fw_ver;
 
-       memset(in_mad, 0, sizeof *in_mad);
-       in_mad->base_version       = 1;
-       in_mad->mgmt_class         = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       in_mad->class_version      = 1;
-       in_mad->method             = IB_MGMT_METHOD_GET;
-       in_mad->attr_id            = IB_SMP_ATTR_NODE_INFO;
+       init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
 
        err = mthca_MAD_IFC(mdev, 1, 1,
                            1, NULL, NULL, in_mad, out_mad,
@@ -87,7 +91,6 @@ static int mthca_query_device(struct ib_device *ibdev,
        props->vendor_part_id      = be16_to_cpup((__be16 *) (out_mad->data + 30));
        props->hw_ver              = be32_to_cpup((__be32 *) (out_mad->data + 32));
        memcpy(&props->sys_image_guid, out_mad->data +  4, 8);
-       memcpy(&props->node_guid,      out_mad->data + 12, 8);
 
        props->max_mr_size         = ~0ull;
        props->page_size_cap       = mdev->limits.page_size_cap;
@@ -128,20 +131,16 @@ static int mthca_query_port(struct ib_device *ibdev,
        int err = -ENOMEM;
        u8 status;
 
-       in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
        out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
        if (!in_mad || !out_mad)
                goto out;
 
        memset(props, 0, sizeof *props);
 
-       memset(in_mad, 0, sizeof *in_mad);
-       in_mad->base_version       = 1;
-       in_mad->mgmt_class         = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       in_mad->class_version      = 1;
-       in_mad->method             = IB_MGMT_METHOD_GET;
-       in_mad->attr_id            = IB_SMP_ATTR_PORT_INFO;
-       in_mad->attr_mod           = cpu_to_be32(port);
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
 
        err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
                            port, NULL, NULL, in_mad, out_mad,
@@ -220,18 +219,14 @@ static int mthca_query_pkey(struct ib_device *ibdev,
        int err = -ENOMEM;
        u8 status;
 
-       in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
        out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
        if (!in_mad || !out_mad)
                goto out;
 
-       memset(in_mad, 0, sizeof *in_mad);
-       in_mad->base_version       = 1;
-       in_mad->mgmt_class         = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       in_mad->class_version      = 1;
-       in_mad->method             = IB_MGMT_METHOD_GET;
-       in_mad->attr_id            = IB_SMP_ATTR_PKEY_TABLE;
-       in_mad->attr_mod           = cpu_to_be32(index / 32);
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PKEY_TABLE;
+       in_mad->attr_mod = cpu_to_be32(index / 32);
 
        err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
                            port, NULL, NULL, in_mad, out_mad,
@@ -259,18 +254,14 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port,
        int err = -ENOMEM;
        u8 status;
 
-       in_mad  = kmalloc(sizeof *in_mad, GFP_KERNEL);
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
        out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
        if (!in_mad || !out_mad)
                goto out;
 
-       memset(in_mad, 0, sizeof *in_mad);
-       in_mad->base_version       = 1;
-       in_mad->mgmt_class         = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       in_mad->class_version      = 1;
-       in_mad->method             = IB_MGMT_METHOD_GET;
-       in_mad->attr_id            = IB_SMP_ATTR_PORT_INFO;
-       in_mad->attr_mod           = cpu_to_be32(port);
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_PORT_INFO;
+       in_mad->attr_mod = cpu_to_be32(port);
 
        err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
                            port, NULL, NULL, in_mad, out_mad,
@@ -284,13 +275,9 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port,
 
        memcpy(gid->raw, out_mad->data + 8, 8);
 
-       memset(in_mad, 0, sizeof *in_mad);
-       in_mad->base_version       = 1;
-       in_mad->mgmt_class         = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       in_mad->class_version      = 1;
-       in_mad->method             = IB_MGMT_METHOD_GET;
-       in_mad->attr_id            = IB_SMP_ATTR_GUID_INFO;
-       in_mad->attr_mod           = cpu_to_be32(index / 8);
+       init_query_mad(in_mad);
+       in_mad->attr_id  = IB_SMP_ATTR_GUID_INFO;
+       in_mad->attr_mod = cpu_to_be32(index / 8);
 
        err = mthca_MAD_IFC(to_mdev(ibdev), 1, 1,
                            port, NULL, NULL, in_mad, out_mad,
@@ -458,8 +445,10 @@ static struct ib_srq *mthca_create_srq(struct ib_pd *pd,
        if (pd->uobject) {
                context = to_mucontext(pd->uobject->context);
 
-               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
-                       return ERR_PTR(-EFAULT);
+               if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+                       err = -EFAULT;
+                       goto err_free;
+               }
 
                err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
                                        context->db_tab, ucmd.db_index,
@@ -535,8 +524,10 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
                if (pd->uobject) {
                        context = to_mucontext(pd->uobject->context);
 
-                       if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+                       if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) {
+                               kfree(qp);
                                return ERR_PTR(-EFAULT);
+                       }
 
                        err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
                                                context->db_tab,
@@ -783,24 +774,20 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
        if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK))
                return ERR_PTR(-EINVAL);
 
-       if (num_phys_buf > 1 &&
-           ((buffer_list[0].addr + buffer_list[0].size) & ~PAGE_MASK))
-               return ERR_PTR(-EINVAL);
-
        mask = 0;
        total_size = 0;
        for (i = 0; i < num_phys_buf; ++i) {
-               if (i != 0 && buffer_list[i].addr & ~PAGE_MASK)
-                       return ERR_PTR(-EINVAL);
-               if (i != 0 && i != num_phys_buf - 1 &&
-                   (buffer_list[i].size & ~PAGE_MASK))
-                       return ERR_PTR(-EINVAL);
+               if (i != 0)
+                       mask |= buffer_list[i].addr;
+               if (i != num_phys_buf - 1)
+                       mask |= buffer_list[i].addr + buffer_list[i].size;
 
                total_size += buffer_list[i].size;
-               if (i > 0)
-                       mask |= buffer_list[i].addr;
        }
 
+       if (mask & ~PAGE_MASK)
+               return ERR_PTR(-EINVAL);
+
        /* Find largest page shift we can use to cover buffers */
        for (shift = PAGE_SHIFT; shift < 31; ++shift)
                if (num_phys_buf > 1) {
@@ -1070,11 +1057,48 @@ static struct class_device_attribute *mthca_class_attributes[] = {
        &class_device_attr_board_id
 };
 
+static int mthca_init_node_data(struct mthca_dev *dev)
+{
+       struct ib_smp *in_mad  = NULL;
+       struct ib_smp *out_mad = NULL;
+       int err = -ENOMEM;
+       u8 status;
+
+       in_mad  = kzalloc(sizeof *in_mad, GFP_KERNEL);
+       out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
+       if (!in_mad || !out_mad)
+               goto out;
+
+       init_query_mad(in_mad);
+       in_mad->attr_id = IB_SMP_ATTR_NODE_INFO;
+
+       err = mthca_MAD_IFC(dev, 1, 1,
+                           1, NULL, NULL, in_mad, out_mad,
+                           &status);
+       if (err)
+               goto out;
+       if (status) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8);
+
+out:
+       kfree(in_mad);
+       kfree(out_mad);
+       return err;
+}
+
 int mthca_register_device(struct mthca_dev *dev)
 {
        int ret;
        int i;
 
+       ret = mthca_init_node_data(dev);
+       if (ret)
+               return ret;
+
        strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
        dev->ib_dev.owner                = THIS_MODULE;
 
index 564b6d51c394ae8c38e407cac17a8b51983d5889..fba608ed7df2fca3c00cff0b4ef762ca9f0c52a5 100644 (file)
@@ -1434,7 +1434,7 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp,
        u16 pkey;
 
        ib_ud_header_init(256, /* assume a MAD */
-                         sqp->ud_header.grh_present,
+                         mthca_ah_grh_present(to_mah(wr->wr.ud.ah)),
                          &sqp->ud_header);
 
        err = mthca_read_ah(dev, to_mah(wr->wr.ud.ah), &sqp->ud_header);
index 9923a15a9996975ace266e077132aecc8944f4d5..e0a5412b7e68042f820a0c6c32261eba3f39d23c 100644 (file)
 #include <linux/config.h>
 #include <linux/kref.h>
 #include <linux/if_infiniband.h>
+#include <linux/mutex.h>
 
 #include <net/neighbour.h>
 
 #include <asm/atomic.h>
-#include <asm/semaphore.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_pack.h>
@@ -123,8 +123,8 @@ struct ipoib_dev_priv {
 
        unsigned long flags;
 
-       struct semaphore mcast_mutex;
-       struct semaphore vlan_mutex;
+       struct mutex mcast_mutex;
+       struct mutex vlan_mutex;
 
        struct rb_root  path_tree;
        struct list_head path_list;
index 23885801b6d2b3efd1cfefc925b8b451eafceff9..86bcdd72a10706260bf2585fe5d3b5e8103e65e5 100644 (file)
@@ -52,7 +52,7 @@ MODULE_PARM_DESC(data_debug_level,
 
 #define        IPOIB_OP_RECV   (1ul << 31)
 
-static DECLARE_MUTEX(pkey_sem);
+static DEFINE_MUTEX(pkey_mutex);
 
 struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
                                 struct ib_pd *pd, struct ib_ah_attr *attr)
@@ -445,25 +445,16 @@ int ipoib_ib_dev_down(struct net_device *dev)
 
        /* Shutdown the P_Key thread if still active */
        if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
-               down(&pkey_sem);
+               mutex_lock(&pkey_mutex);
                set_bit(IPOIB_PKEY_STOP, &priv->flags);
                cancel_delayed_work(&priv->pkey_task);
-               up(&pkey_sem);
+               mutex_unlock(&pkey_mutex);
                flush_workqueue(ipoib_workqueue);
        }
 
        ipoib_mcast_stop_thread(dev, 1);
-
-       /*
-        * Flush the multicast groups first so we stop any multicast joins. The
-        * completion thread may have already died and we may deadlock waiting
-        * for the completion thread to finish some multicast joins.
-        */
        ipoib_mcast_dev_flush(dev);
 
-       /* Delete broadcast and local addresses since they will be recreated */
-       ipoib_mcast_dev_down(dev);
-
        ipoib_flush_paths(dev);
 
        return 0;
@@ -608,13 +599,13 @@ void ipoib_ib_dev_flush(void *_dev)
        if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
                ipoib_ib_dev_up(dev);
 
-       down(&priv->vlan_mutex);
+       mutex_lock(&priv->vlan_mutex);
 
        /* Flush any child interfaces too */
        list_for_each_entry(cpriv, &priv->child_intfs, list)
                ipoib_ib_dev_flush(&cpriv->dev);
 
-       up(&priv->vlan_mutex);
+       mutex_unlock(&priv->vlan_mutex);
 }
 
 void ipoib_ib_dev_cleanup(struct net_device *dev)
@@ -624,9 +615,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev)
        ipoib_dbg(priv, "cleaning up ib_dev\n");
 
        ipoib_mcast_stop_thread(dev, 1);
-
-       /* Delete the broadcast address and the local address */
-       ipoib_mcast_dev_down(dev);
+       ipoib_mcast_dev_flush(dev);
 
        ipoib_transport_dev_cleanup(dev);
 }
@@ -662,12 +651,12 @@ void ipoib_pkey_poll(void *dev_ptr)
        if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
                ipoib_open(dev);
        else {
-               down(&pkey_sem);
+               mutex_lock(&pkey_mutex);
                if (!test_bit(IPOIB_PKEY_STOP, &priv->flags))
                        queue_delayed_work(ipoib_workqueue,
                                           &priv->pkey_task,
                                           HZ);
-               up(&pkey_sem);
+               mutex_unlock(&pkey_mutex);
        }
 }
 
@@ -681,12 +670,12 @@ int ipoib_pkey_dev_delay_open(struct net_device *dev)
 
        /* P_Key value not assigned yet - start polling */
        if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) {
-               down(&pkey_sem);
+               mutex_lock(&pkey_mutex);
                clear_bit(IPOIB_PKEY_STOP, &priv->flags);
                queue_delayed_work(ipoib_workqueue,
                                   &priv->pkey_task,
                                   HZ);
-               up(&pkey_sem);
+               mutex_unlock(&pkey_mutex);
                return 1;
        }
 
index 780009c7eaa651f908e78def9a8106eea752cd81..fd3f5c862a5d92aef6b61202768bf9c29b24ccbe 100644 (file)
@@ -105,7 +105,7 @@ int ipoib_open(struct net_device *dev)
                struct ipoib_dev_priv *cpriv;
 
                /* Bring up any child interfaces too */
-               down(&priv->vlan_mutex);
+               mutex_lock(&priv->vlan_mutex);
                list_for_each_entry(cpriv, &priv->child_intfs, list) {
                        int flags;
 
@@ -115,7 +115,7 @@ int ipoib_open(struct net_device *dev)
 
                        dev_change_flags(cpriv->dev, flags | IFF_UP);
                }
-               up(&priv->vlan_mutex);
+               mutex_unlock(&priv->vlan_mutex);
        }
 
        netif_start_queue(dev);
@@ -140,7 +140,7 @@ static int ipoib_stop(struct net_device *dev)
                struct ipoib_dev_priv *cpriv;
 
                /* Bring down any child interfaces too */
-               down(&priv->vlan_mutex);
+               mutex_lock(&priv->vlan_mutex);
                list_for_each_entry(cpriv, &priv->child_intfs, list) {
                        int flags;
 
@@ -150,7 +150,7 @@ static int ipoib_stop(struct net_device *dev)
 
                        dev_change_flags(cpriv->dev, flags & ~IFF_UP);
                }
-               up(&priv->vlan_mutex);
+               mutex_unlock(&priv->vlan_mutex);
        }
 
        return 0;
@@ -892,8 +892,8 @@ static void ipoib_setup(struct net_device *dev)
        spin_lock_init(&priv->lock);
        spin_lock_init(&priv->tx_lock);
 
-       init_MUTEX(&priv->mcast_mutex);
-       init_MUTEX(&priv->vlan_mutex);
+       mutex_init(&priv->mcast_mutex);
+       mutex_init(&priv->vlan_mutex);
 
        INIT_LIST_HEAD(&priv->path_list);
        INIT_LIST_HEAD(&priv->child_intfs);
index ed0c2ead8bc16f0c215a054f0c765d4d2a440eee..98039da0caf0e4ff67e958c3679540f4030b12a9 100644 (file)
@@ -55,7 +55,7 @@ MODULE_PARM_DESC(mcast_debug_level,
                 "Enable multicast debug tracing if > 0");
 #endif
 
-static DECLARE_MUTEX(mcast_mutex);
+static DEFINE_MUTEX(mcast_mutex);
 
 /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
 struct ipoib_mcast {
@@ -97,8 +97,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_neigh *neigh, *tmp;
        unsigned long flags;
-       LIST_HEAD(ah_list);
-       struct ipoib_ah *ah, *tah;
 
        ipoib_dbg_mcast(netdev_priv(dev),
                        "deleting multicast group " IPOIB_GID_FMT "\n",
@@ -107,8 +105,14 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
        spin_lock_irqsave(&priv->lock, flags);
 
        list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {
+               /*
+                * It's safe to call ipoib_put_ah() inside priv->lock
+                * here, because we know that mcast->ah will always
+                * hold one more reference, so ipoib_put_ah() will
+                * never do more than decrement the ref count.
+                */
                if (neigh->ah)
-                       list_add_tail(&neigh->ah->list, &ah_list);
+                       ipoib_put_ah(neigh->ah);
                *to_ipoib_neigh(neigh->neighbour) = NULL;
                neigh->neighbour->ops->destructor = NULL;
                kfree(neigh);
@@ -116,9 +120,6 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       list_for_each_entry_safe(ah, tah, &ah_list, list)
-               ipoib_put_ah(ah);
-
        if (mcast->ah)
                ipoib_put_ah(mcast->ah);
 
@@ -384,10 +385,10 @@ static void ipoib_mcast_join_complete(int status,
 
        if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) {
                mcast->backoff = 1;
-               down(&mcast_mutex);
+               mutex_lock(&mcast_mutex);
                if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
                        queue_work(ipoib_workqueue, &priv->mcast_task);
-               up(&mcast_mutex);
+               mutex_unlock(&mcast_mutex);
                complete(&mcast->done);
                return;
        }
@@ -417,7 +418,7 @@ static void ipoib_mcast_join_complete(int status,
 
        mcast->query = NULL;
 
-       down(&mcast_mutex);
+       mutex_lock(&mcast_mutex);
        if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {
                if (status == -ETIMEDOUT)
                        queue_work(ipoib_workqueue, &priv->mcast_task);
@@ -426,7 +427,7 @@ static void ipoib_mcast_join_complete(int status,
                                           mcast->backoff * HZ);
        } else
                complete(&mcast->done);
-       up(&mcast_mutex);
+       mutex_unlock(&mcast_mutex);
 
        return;
 }
@@ -481,12 +482,12 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
                if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
                        mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
 
-               down(&mcast_mutex);
+               mutex_lock(&mcast_mutex);
                if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
                        queue_delayed_work(ipoib_workqueue,
                                           &priv->mcast_task,
                                           mcast->backoff * HZ);
-               up(&mcast_mutex);
+               mutex_unlock(&mcast_mutex);
        } else
                mcast->query_id = ret;
 }
@@ -519,11 +520,11 @@ void ipoib_mcast_join_task(void *dev_ptr)
                priv->broadcast = ipoib_mcast_alloc(dev, 1);
                if (!priv->broadcast) {
                        ipoib_warn(priv, "failed to allocate broadcast group\n");
-                       down(&mcast_mutex);
+                       mutex_lock(&mcast_mutex);
                        if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
                                queue_delayed_work(ipoib_workqueue,
                                                   &priv->mcast_task, HZ);
-                       up(&mcast_mutex);
+                       mutex_unlock(&mcast_mutex);
                        return;
                }
 
@@ -579,10 +580,10 @@ int ipoib_mcast_start_thread(struct net_device *dev)
 
        ipoib_dbg_mcast(priv, "starting multicast thread\n");
 
-       down(&mcast_mutex);
+       mutex_lock(&mcast_mutex);
        if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags))
                queue_work(ipoib_workqueue, &priv->mcast_task);
-       up(&mcast_mutex);
+       mutex_unlock(&mcast_mutex);
 
        return 0;
 }
@@ -594,10 +595,10 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
 
        ipoib_dbg_mcast(priv, "stopping multicast thread\n");
 
-       down(&mcast_mutex);
+       mutex_lock(&mcast_mutex);
        clear_bit(IPOIB_MCAST_RUN, &priv->flags);
        cancel_delayed_work(&priv->mcast_task);
-       up(&mcast_mutex);
+       mutex_unlock(&mcast_mutex);
 
        if (flush)
                flush_workqueue(ipoib_workqueue);
@@ -741,48 +742,23 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        LIST_HEAD(remove_list);
-       struct ipoib_mcast *mcast, *tmcast, *nmcast;
+       struct ipoib_mcast *mcast, *tmcast;
        unsigned long flags;
 
        ipoib_dbg_mcast(priv, "flushing multicast list\n");
 
        spin_lock_irqsave(&priv->lock, flags);
-       list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) {
-               nmcast = ipoib_mcast_alloc(dev, 0);
-               if (nmcast) {
-                       nmcast->flags =
-                               mcast->flags & (1 << IPOIB_MCAST_FLAG_SENDONLY);
 
-                       nmcast->mcmember.mgid = mcast->mcmember.mgid;
-
-                       /* Add the new group in before the to-be-destroyed group */
-                       list_add_tail(&nmcast->list, &mcast->list);
-                       list_del_init(&mcast->list);
-
-                       rb_replace_node(&mcast->rb_node, &nmcast->rb_node,
-                                       &priv->multicast_tree);
-
-                       list_add_tail(&mcast->list, &remove_list);
-               } else {
-                       ipoib_warn(priv, "could not reallocate multicast group "
-                                  IPOIB_GID_FMT "\n",
-                                  IPOIB_GID_ARG(mcast->mcmember.mgid));
-               }
+       list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) {
+               list_del(&mcast->list);
+               rb_erase(&mcast->rb_node, &priv->multicast_tree);
+               list_add_tail(&mcast->list, &remove_list);
        }
 
        if (priv->broadcast) {
-               nmcast = ipoib_mcast_alloc(dev, 0);
-               if (nmcast) {
-                       nmcast->mcmember.mgid = priv->broadcast->mcmember.mgid;
-
-                       rb_replace_node(&priv->broadcast->rb_node,
-                                       &nmcast->rb_node,
-                                       &priv->multicast_tree);
-
-                       list_add_tail(&priv->broadcast->list, &remove_list);
-               }
-
-               priv->broadcast = nmcast;
+               rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
+               list_add_tail(&priv->broadcast->list, &remove_list);
+               priv->broadcast = NULL;
        }
 
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -793,24 +769,6 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
        }
 }
 
-void ipoib_mcast_dev_down(struct net_device *dev)
-{
-       struct ipoib_dev_priv *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       /* Delete broadcast since it will be recreated */
-       if (priv->broadcast) {
-               ipoib_dbg_mcast(priv, "deleting broadcast group\n");
-
-               spin_lock_irqsave(&priv->lock, flags);
-               rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               ipoib_mcast_leave(dev, priv->broadcast);
-               ipoib_mcast_free(priv->broadcast);
-               priv->broadcast = NULL;
-       }
-}
-
 void ipoib_mcast_restart_task(void *dev_ptr)
 {
        struct net_device *dev = dev_ptr;
@@ -824,7 +782,8 @@ void ipoib_mcast_restart_task(void *dev_ptr)
 
        ipoib_mcast_stop_thread(dev, 0);
 
-       spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&dev->xmit_lock, flags);
+       spin_lock(&priv->lock);
 
        /*
         * Unfortunately, the networking core only gives us a list of all of
@@ -896,7 +855,9 @@ void ipoib_mcast_restart_task(void *dev_ptr)
                        list_add_tail(&mcast->list, &remove_list);
                }
        }
-       spin_unlock_irqrestore(&priv->lock, flags);
+
+       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&dev->xmit_lock, flags);
 
        /* We have to cancel outside of the spinlock */
        list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
index e829e10400e35436a38b24860974e984a3aff40f..faaf10e5fc7b0b7eaee6ccb1bd1ef217595d902d 100644 (file)
@@ -65,9 +65,9 @@ int ipoib_mcast_attach(struct net_device *dev, u16 mlid, union ib_gid *mgid)
        }
 
        /* attach QP to multicast group */
-       down(&priv->mcast_mutex);
+       mutex_lock(&priv->mcast_mutex);
        ret = ib_attach_mcast(priv->qp, mgid, mlid);
-       up(&priv->mcast_mutex);
+       mutex_unlock(&priv->mcast_mutex);
        if (ret)
                ipoib_warn(priv, "failed to attach to multicast group, ret = %d\n", ret);
 
@@ -81,9 +81,9 @@ int ipoib_mcast_detach(struct net_device *dev, u16 mlid, union ib_gid *mgid)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        int ret;
 
-       down(&priv->mcast_mutex);
+       mutex_lock(&priv->mcast_mutex);
        ret = ib_detach_mcast(priv->qp, mgid, mlid);
-       up(&priv->mcast_mutex);
+       mutex_unlock(&priv->mcast_mutex);
        if (ret)
                ipoib_warn(priv, "ib_detach_mcast failed (result = %d)\n", ret);
 
index d280b341a37fa25bff8323778ddc2fc87ecad67c..4ca175553f9f71201ff6a6ad604093e24e88950b 100644 (file)
@@ -63,7 +63,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
 
        ppriv = netdev_priv(pdev);
 
-       down(&ppriv->vlan_mutex);
+       mutex_lock(&ppriv->vlan_mutex);
 
        /*
         * First ensure this isn't a duplicate. We check the parent device and
@@ -124,7 +124,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
 
        list_add_tail(&priv->list, &ppriv->child_intfs);
 
-       up(&ppriv->vlan_mutex);
+       mutex_unlock(&ppriv->vlan_mutex);
 
        return 0;
 
@@ -139,7 +139,7 @@ device_init_failed:
        free_netdev(priv->dev);
 
 err:
-       up(&ppriv->vlan_mutex);
+       mutex_unlock(&ppriv->vlan_mutex);
        return result;
 }
 
@@ -153,7 +153,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
 
        ppriv = netdev_priv(pdev);
 
-       down(&ppriv->vlan_mutex);
+       mutex_lock(&ppriv->vlan_mutex);
        list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
                if (priv->pkey == pkey) {
                        unregister_netdev(priv->dev);
@@ -167,7 +167,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
                        break;
                }
        }
-       up(&ppriv->vlan_mutex);
+       mutex_unlock(&ppriv->vlan_mutex);
 
        return ret;
 }
index dd488d3cffa93c9b11316765750fe28005a6e148..31207e664148e440d44790bc5f4cb85a31d66fb9 100644 (file)
@@ -1516,8 +1516,7 @@ static ssize_t show_port(struct class_device *class_dev, char *buf)
 
 static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
 
-static struct srp_host *srp_add_port(struct ib_device *device,
-                                    __be64 node_guid, u8 port)
+static struct srp_host *srp_add_port(struct ib_device *device, u8 port)
 {
        struct srp_host *host;
 
@@ -1532,7 +1531,7 @@ static struct srp_host *srp_add_port(struct ib_device *device,
        host->port = port;
 
        host->initiator_port_id[7] = port;
-       memcpy(host->initiator_port_id + 8, &node_guid, 8);
+       memcpy(host->initiator_port_id + 8, &device->node_guid, 8);
 
        host->pd   = ib_alloc_pd(device);
        if (IS_ERR(host->pd))
@@ -1580,22 +1579,11 @@ static void srp_add_one(struct ib_device *device)
 {
        struct list_head *dev_list;
        struct srp_host *host;
-       struct ib_device_attr *dev_attr;
        int s, e, p;
 
-       dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
-       if (!dev_attr)
-               return;
-
-       if (ib_query_device(device, dev_attr)) {
-               printk(KERN_WARNING PFX "Couldn't query node GUID for %s.\n",
-                      device->name);
-               goto out;
-       }
-
        dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
        if (!dev_list)
-               goto out;
+               return;
 
        INIT_LIST_HEAD(dev_list);
 
@@ -1608,15 +1596,12 @@ static void srp_add_one(struct ib_device *device)
        }
 
        for (p = s; p <= e; ++p) {
-               host = srp_add_port(device, dev_attr->node_guid, p);
+               host = srp_add_port(device, p);
                if (host)
                        list_add_tail(&host->list, dev_list);
        }
 
        ib_set_client_data(device, &srp_client, dev_list);
-
-out:
-       kfree(dev_attr);
 }
 
 static void srp_remove_one(struct ib_device *device)
index caac6d63d46f4a7da7ffc70293aad635d7c6bb37..b765a155c0088db9c29cad78ca8fd3f9810ac838 100644 (file)
@@ -50,9 +50,7 @@ static DECLARE_MUTEX(gameport_sem);
 
 static LIST_HEAD(gameport_list);
 
-static struct bus_type gameport_bus = {
-       .name = "gameport",
-};
+static struct bus_type gameport_bus;
 
 static void gameport_add_port(struct gameport *gameport);
 static void gameport_destroy_port(struct gameport *gameport);
@@ -703,11 +701,15 @@ static int gameport_driver_remove(struct device *dev)
        return 0;
 }
 
+static struct bus_type gameport_bus = {
+       .name = "gameport",
+       .probe = gameport_driver_probe,
+       .remove = gameport_driver_remove,
+};
+
 void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
 {
        drv->driver.bus = &gameport_bus;
-       drv->driver.probe = gameport_driver_probe;
-       drv->driver.remove = gameport_driver_remove;
        gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
 }
 
index fe33ff334e27cf48d27d366df69ab4249a206842..4fe3da3c667a0ecfa06eefad1759d831aa7f014f 100644 (file)
@@ -528,40 +528,56 @@ INPUT_DEV_STRING_ATTR_SHOW(name);
 INPUT_DEV_STRING_ATTR_SHOW(phys);
 INPUT_DEV_STRING_ATTR_SHOW(uniq);
 
-static int print_modalias_bits(char *buf, char prefix, unsigned long *arr,
+static int print_modalias_bits(char *buf, int size, char prefix, unsigned long *arr,
                               unsigned int min, unsigned int max)
 {
        int len, i;
 
-       len = sprintf(buf, "%c", prefix);
+       len = snprintf(buf, size, "%c", prefix);
        for (i = min; i < max; i++)
                if (arr[LONG(i)] & BIT(i))
-                       len += sprintf(buf+len, "%X,", i);
+                       len += snprintf(buf + len, size - len, "%X,", i);
        return len;
 }
 
-static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf)
+static int print_modalias(char *buf, int size, struct input_dev *id)
 {
-       struct input_dev *id = to_input_dev(dev);
-       ssize_t len = 0;
+       int len;
 
-       len += sprintf(buf+len, "input:b%04Xv%04Xp%04Xe%04X-",
+       len = snprintf(buf, size, "input:b%04Xv%04Xp%04Xe%04X-",
                       id->id.bustype,
                       id->id.vendor,
                       id->id.product,
                       id->id.version);
 
-       len += print_modalias_bits(buf+len, 'e', id->evbit, 0, EV_MAX);
-       len += print_modalias_bits(buf+len, 'k', id->keybit,
+       len += print_modalias_bits(buf + len, size - len, 'e', id->evbit,
+                                  0, EV_MAX);
+       len += print_modalias_bits(buf + len, size - len, 'k', id->keybit,
                                   KEY_MIN_INTERESTING, KEY_MAX);
-       len += print_modalias_bits(buf+len, 'r', id->relbit, 0, REL_MAX);
-       len += print_modalias_bits(buf+len, 'a', id->absbit, 0, ABS_MAX);
-       len += print_modalias_bits(buf+len, 'm', id->mscbit, 0, MSC_MAX);
-       len += print_modalias_bits(buf+len, 'l', id->ledbit, 0, LED_MAX);
-       len += print_modalias_bits(buf+len, 's', id->sndbit, 0, SND_MAX);
-       len += print_modalias_bits(buf+len, 'f', id->ffbit, 0, FF_MAX);
-       len += print_modalias_bits(buf+len, 'w', id->swbit, 0, SW_MAX);
-       len += sprintf(buf+len, "\n");
+       len += print_modalias_bits(buf + len, size - len, 'r', id->relbit,
+                                  0, REL_MAX);
+       len += print_modalias_bits(buf + len, size - len, 'a', id->absbit,
+                                  0, ABS_MAX);
+       len += print_modalias_bits(buf + len, size - len, 'm', id->mscbit,
+                                  0, MSC_MAX);
+       len += print_modalias_bits(buf + len, size - len, 'l', id->ledbit,
+                                  0, LED_MAX);
+       len += print_modalias_bits(buf + len, size - len, 's', id->sndbit,
+                                  0, SND_MAX);
+       len += print_modalias_bits(buf + len, size - len, 'f', id->ffbit,
+                                  0, FF_MAX);
+       len += print_modalias_bits(buf + len, size - len, 'w', id->swbit,
+                                  0, SW_MAX);
+       return len;
+}
+
+static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf)
+{
+       struct input_dev *id = to_input_dev(dev);
+       ssize_t len;
+
+       len = print_modalias(buf, PAGE_SIZE, id);
+       len += snprintf(buf + len, PAGE_SIZE-len, "\n");
        return len;
 }
 static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
@@ -728,8 +744,11 @@ static int input_dev_uevent(struct class_device *cdev, char **envp,
        if (test_bit(EV_SW, dev->evbit))
                INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX);
 
-       envp[i] = NULL;
+       envp[i++] = buffer + len;
+       len += snprintf(buffer + len, buffer_size - len, "MODALIAS=");
+       len += print_modalias(buffer + len, buffer_size - len, dev) + 1;
 
+       envp[i] = NULL;
        return 0;
 }
 
index 24474335dfd1f38fb171817b844e3c8ec6a24771..2141501e9f2e498246df66233623490ade12494a 100644 (file)
@@ -348,6 +348,40 @@ static int alps_tap_mode(struct psmouse *psmouse, int enable)
        return 0;
 }
 
+/*
+ * alps_poll() - poll the touchpad for current motion packet.
+ * Used in resync.
+ */
+static int alps_poll(struct psmouse *psmouse)
+{
+       struct alps_data *priv = psmouse->private;
+       unsigned char buf[6];
+       int poll_failed;
+
+       if (priv->i->flags & ALPS_PASS)
+               alps_passthrough_mode(psmouse, 1);
+
+       poll_failed = ps2_command(&psmouse->ps2dev, buf,
+                                 PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
+
+       if (priv->i->flags & ALPS_PASS)
+               alps_passthrough_mode(psmouse, 0);
+
+       if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
+               return -1;
+
+       if ((psmouse->badbyte & 0xc8) == 0x08) {
+/*
+ * Poll the track stick ...
+ */
+               if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8)))
+                       return -1;
+       }
+
+       memcpy(psmouse->packet, buf, sizeof(buf));
+       return 0;
+}
+
 static int alps_reconnect(struct psmouse *psmouse)
 {
        struct alps_data *priv = psmouse->private;
@@ -451,10 +485,14 @@ int alps_init(struct psmouse *psmouse)
        input_register_device(priv->dev2);
 
        psmouse->protocol_handler = alps_process_byte;
+       psmouse->poll = alps_poll;
        psmouse->disconnect = alps_disconnect;
        psmouse->reconnect = alps_reconnect;
        psmouse->pktsize = 6;
 
+       /* We are having trouble resyncing ALPS touchpads so disable it for now */
+       psmouse->resync_time = 0;
+
        return 0;
 
 init_fail:
index 025a71de540415ce58ca3be10c94b0ae80ac66e3..c88520d3d13cadc2c6b03819ab2ff9ade3861dd5 100644 (file)
@@ -117,7 +117,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
        if (psmouse_sliced_command(psmouse, command))
                return -1;
 
-       if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL))
+       if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300))
                return -1;
 
        return 0;
index 4d5ecc04c5b65382d5b8de27c345e2ba8813e05e..7665fd9ce559c49a153289bd64e19d6255134c11 100644 (file)
@@ -54,10 +54,14 @@ static unsigned int psmouse_smartscroll = 1;
 module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
 MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
 
-static unsigned int psmouse_resetafter;
+static unsigned int psmouse_resetafter = 5;
 module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 
+static unsigned int psmouse_resync_time = 5;
+module_param_named(resync_time, psmouse_resync_time, uint, 0644);
+MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never).");
+
 PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO,
                        NULL,
                        psmouse_attr_show_protocol, psmouse_attr_set_protocol);
@@ -70,12 +74,16 @@ PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO,
 PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO,
                        (void *) offsetof(struct psmouse, resetafter),
                        psmouse_show_int_attr, psmouse_set_int_attr);
+PSMOUSE_DEFINE_ATTR(resync_time, S_IWUSR | S_IRUGO,
+                       (void *) offsetof(struct psmouse, resync_time),
+                       psmouse_show_int_attr, psmouse_set_int_attr);
 
 static struct attribute *psmouse_attributes[] = {
        &psmouse_attr_protocol.dattr.attr,
        &psmouse_attr_rate.dattr.attr,
        &psmouse_attr_resolution.dattr.attr,
        &psmouse_attr_resetafter.dattr.attr,
+       &psmouse_attr_resync_time.dattr.attr,
        NULL
 };
 
@@ -98,6 +106,8 @@ __obsolete_setup("psmouse_rate=");
  */
 static DECLARE_MUTEX(psmouse_sem);
 
+static struct workqueue_struct *kpsmoused_wq;
+
 struct psmouse_protocol {
        enum psmouse_type type;
        char *name;
@@ -178,15 +188,79 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_reg
 }
 
 /*
- * psmouse_interrupt() handles incoming characters, either gathering them into
- * packets or passing them to the command routine as command output.
+ * __psmouse_set_state() sets new psmouse state and resets all flags.
+ */
+
+static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
+{
+       psmouse->state = new_state;
+       psmouse->pktcnt = psmouse->out_of_sync = 0;
+       psmouse->ps2dev.flags = 0;
+       psmouse->last = jiffies;
+}
+
+
+/*
+ * psmouse_set_state() sets new psmouse state and resets all flags and
+ * counters while holding serio lock so fighting with interrupt handler
+ * is not a concern.
+ */
+
+static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
+{
+       serio_pause_rx(psmouse->ps2dev.serio);
+       __psmouse_set_state(psmouse, new_state);
+       serio_continue_rx(psmouse->ps2dev.serio);
+}
+
+/*
+ * psmouse_handle_byte() processes one byte of the input data stream
+ * by calling corresponding protocol handler.
+ */
+
+static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+       psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs);
+
+       switch (rc) {
+               case PSMOUSE_BAD_DATA:
+                       if (psmouse->state == PSMOUSE_ACTIVATED) {
+                               printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
+                                       psmouse->name, psmouse->phys, psmouse->pktcnt);
+                               if (++psmouse->out_of_sync == psmouse->resetafter) {
+                                       __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+                                       printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
+                                       serio_reconnect(psmouse->ps2dev.serio);
+                                       return -1;
+                               }
+                       }
+                       psmouse->pktcnt = 0;
+                       break;
+
+               case PSMOUSE_FULL_PACKET:
+                       psmouse->pktcnt = 0;
+                       if (psmouse->out_of_sync) {
+                               psmouse->out_of_sync = 0;
+                               printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
+                                       psmouse->name, psmouse->phys);
+                       }
+                       break;
+
+               case PSMOUSE_GOOD_DATA:
+                       break;
+       }
+       return 0;
+}
+
+/*
+ * psmouse_interrupt() handles incoming characters, either passing them
+ * for normal processing or gathering them as command response.
  */
 
 static irqreturn_t psmouse_interrupt(struct serio *serio,
                unsigned char data, unsigned int flags, struct pt_regs *regs)
 {
        struct psmouse *psmouse = serio_get_drvdata(serio);
-       psmouse_ret_t rc;
 
        if (psmouse->state == PSMOUSE_IGNORE)
                goto out;
@@ -208,67 +282,58 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
                if  (ps2_handle_response(&psmouse->ps2dev, data))
                        goto out;
 
-       if (psmouse->state == PSMOUSE_INITIALIZING)
+       if (psmouse->state <= PSMOUSE_RESYNCING)
                goto out;
 
        if (psmouse->state == PSMOUSE_ACTIVATED &&
            psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
-               printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
+               printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
                       psmouse->name, psmouse->phys, psmouse->pktcnt);
-               psmouse->pktcnt = 0;
+               psmouse->badbyte = psmouse->packet[0];
+               __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
+               queue_work(kpsmoused_wq, &psmouse->resync_work);
+               goto out;
        }
 
-       psmouse->last = jiffies;
        psmouse->packet[psmouse->pktcnt++] = data;
-
-       if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
+/*
+ * Check if this is a new device announcement (0xAA 0x00)
+ */
+       if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
                if (psmouse->pktcnt == 1)
                        goto out;
 
-               if (psmouse->pktcnt == 2) {
-                       if (psmouse->packet[1] == PSMOUSE_RET_ID) {
-                               psmouse->state = PSMOUSE_IGNORE;
-                               serio_reconnect(serio);
-                               goto out;
-                       }
-                       if (psmouse->type == PSMOUSE_SYNAPTICS) {
-                               /* neither 0xAA nor 0x00 are valid first bytes
-                                * for a packet in absolute mode
-                                */
-                               psmouse->pktcnt = 0;
-                               goto out;
-                       }
+               if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+                       __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+                       serio_reconnect(serio);
+                       goto out;
                }
-       }
-
-       rc = psmouse->protocol_handler(psmouse, regs);
+/*
+ * Not a new device, try processing first byte normally
+ */
+               psmouse->pktcnt = 1;
+               if (psmouse_handle_byte(psmouse, regs))
+                       goto out;
 
-       switch (rc) {
-               case PSMOUSE_BAD_DATA:
-                       printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
-                               psmouse->name, psmouse->phys, psmouse->pktcnt);
-                       psmouse->pktcnt = 0;
+               psmouse->packet[psmouse->pktcnt++] = data;
+       }
 
-                       if (++psmouse->out_of_sync == psmouse->resetafter) {
-                               psmouse->state = PSMOUSE_IGNORE;
-                               printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
-                               serio_reconnect(psmouse->ps2dev.serio);
-                       }
-                       break;
+/*
+ * See if we need to force resync because mouse was idle for too long
+ */
+       if (psmouse->state == PSMOUSE_ACTIVATED &&
+           psmouse->pktcnt == 1 && psmouse->resync_time &&
+           time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
+               psmouse->badbyte = psmouse->packet[0];
+               __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
+               queue_work(kpsmoused_wq, &psmouse->resync_work);
+               goto out;
+       }
 
-               case PSMOUSE_FULL_PACKET:
-                       psmouse->pktcnt = 0;
-                       if (psmouse->out_of_sync) {
-                               psmouse->out_of_sync = 0;
-                               printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
-                                       psmouse->name, psmouse->phys);
-                       }
-                       break;
+       psmouse->last = jiffies;
+       psmouse_handle_byte(psmouse, regs);
 
-               case PSMOUSE_GOOD_DATA:
-                       break;
-       }
-out:
+ out:
        return IRQ_HANDLED;
 }
 
@@ -751,21 +816,6 @@ static void psmouse_initialize(struct psmouse *psmouse)
        }
 }
 
-/*
- * psmouse_set_state() sets new psmouse state and resets all flags and
- * counters while holding serio lock so fighting with interrupt handler
- * is not a concern.
- */
-
-static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
-{
-       serio_pause_rx(psmouse->ps2dev.serio);
-       psmouse->state = new_state;
-       psmouse->pktcnt = psmouse->out_of_sync = 0;
-       psmouse->ps2dev.flags = 0;
-       serio_continue_rx(psmouse->ps2dev.serio);
-}
-
 /*
  * psmouse_activate() enables the mouse so that we get motion reports from it.
  */
@@ -794,6 +844,111 @@ static void psmouse_deactivate(struct psmouse *psmouse)
        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 }
 
+/*
+ * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it.
+ */
+
+static int psmouse_poll(struct psmouse *psmouse)
+{
+       return ps2_command(&psmouse->ps2dev, psmouse->packet,
+                          PSMOUSE_CMD_POLL | (psmouse->pktsize << 8));
+}
+
+
+/*
+ * psmouse_resync() attempts to re-validate current protocol.
+ */
+
+static void psmouse_resync(void *p)
+{
+       struct psmouse *psmouse = p, *parent = NULL;
+       struct serio *serio = psmouse->ps2dev.serio;
+       psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
+       int failed = 0, enabled = 0;
+       int i;
+
+       down(&psmouse_sem);
+
+       if (psmouse->state != PSMOUSE_RESYNCING)
+               goto out;
+
+       if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+               parent = serio_get_drvdata(serio->parent);
+               psmouse_deactivate(parent);
+       }
+
+/*
+ * Some mice don't ACK commands sent while they are in the middle of
+ * transmitting motion packet. To avoid delay we use ps2_sendbyte()
+ * instead of ps2_command() which would wait for 200ms for an ACK
+ * that may never come.
+ * As an additional quirk ALPS touchpads may not only forget to ACK
+ * disable command but will stop reporting taps, so if we see that
+ * mouse at least once ACKs disable we will do full reconnect if ACK
+ * is missing.
+ */
+       psmouse->num_resyncs++;
+
+       if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) {
+               if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command)
+                       failed = 1;
+       } else
+               psmouse->acks_disable_command = 1;
+
+/*
+ * Poll the mouse. If it was reset the packet will be shorter than
+ * psmouse->pktsize and ps2_command will fail. We do not expect and
+ * do not handle scenario when mouse "upgrades" its protocol while
+ * disconnected since it would require additional delay. If we ever
+ * see a mouse that does it we'll adjust the code.
+ */
+       if (!failed) {
+               if (psmouse->poll(psmouse))
+                       failed = 1;
+               else {
+                       psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+                       for (i = 0; i < psmouse->pktsize; i++) {
+                               psmouse->pktcnt++;
+                               rc = psmouse->protocol_handler(psmouse, NULL);
+                               if (rc != PSMOUSE_GOOD_DATA)
+                                       break;
+                       }
+                       if (rc != PSMOUSE_FULL_PACKET)
+                               failed = 1;
+                       psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
+               }
+       }
+/*
+ * Now try to enable mouse. We try to do that even if poll failed and also
+ * repeat our attempts 5 times, otherwise we may be left out with disabled
+ * mouse.
+ */
+       for (i = 0; i < 5; i++) {
+               if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
+                       enabled = 1;
+                       break;
+               }
+               msleep(200);
+       }
+
+       if (!enabled) {
+               printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n",
+                       psmouse->ps2dev.serio->phys);
+               failed = 1;
+       }
+
+       if (failed) {
+               psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+               printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n");
+               serio_reconnect(serio);
+       } else
+               psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
+
+       if (parent)
+               psmouse_activate(parent);
+ out:
+       up(&psmouse_sem);
+}
 
 /*
  * psmouse_cleanup() resets the mouse into power-on state.
@@ -822,6 +977,11 @@ static void psmouse_disconnect(struct serio *serio)
 
        psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 
+       /* make sure we don't have a resync in progress */
+       up(&psmouse_sem);
+       flush_workqueue(kpsmoused_wq);
+       down(&psmouse_sem);
+
        if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
                parent = serio_get_drvdata(serio->parent);
                psmouse_deactivate(parent);
@@ -859,6 +1019,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto
 
        psmouse->set_rate = psmouse_set_rate;
        psmouse->set_resolution = psmouse_set_resolution;
+       psmouse->poll = psmouse_poll;
        psmouse->protocol_handler = psmouse_process_byte;
        psmouse->pktsize = 3;
 
@@ -874,6 +1035,23 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto
        else
                psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
 
+       /*
+        * If mouse's packet size is 3 there is no point in polling the
+        * device in hopes to detect protocol reset - we won't get less
+        * than 3 bytes response anyhow.
+        */
+       if (psmouse->pktsize == 3)
+               psmouse->resync_time = 0;
+
+       /*
+        * Some smart KVMs fake response to POLL command returning just
+        * 3 bytes and messing up our resync logic, so if initial poll
+        * fails we won't try polling the device anymore. Hopefully
+        * such KVM will maintain initially selected protocol.
+        */
+       if (psmouse->resync_time && psmouse->poll(psmouse))
+               psmouse->resync_time = 0;
+
        sprintf(psmouse->devname, "%s %s %s",
                psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
 
@@ -914,6 +1092,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
                goto out;
 
        ps2_init(&psmouse->ps2dev, serio);
+       INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse);
        psmouse->dev = input_dev;
        sprintf(psmouse->phys, "%s/input0", serio->phys);
 
@@ -934,6 +1113,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
        psmouse->rate = psmouse_rate;
        psmouse->resolution = psmouse_resolution;
        psmouse->resetafter = psmouse_resetafter;
+       psmouse->resync_time = parent ? 0 : psmouse_resync_time;
        psmouse->smartscroll = psmouse_smartscroll;
 
        psmouse_switch_protocol(psmouse, NULL);
@@ -1278,13 +1458,21 @@ static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 
 static int __init psmouse_init(void)
 {
+       kpsmoused_wq = create_singlethread_workqueue("kpsmoused");
+       if (!kpsmoused_wq) {
+               printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n");
+               return -ENOMEM;
+       }
+
        serio_register_driver(&psmouse_drv);
+
        return 0;
 }
 
 static void __exit psmouse_exit(void)
 {
        serio_unregister_driver(&psmouse_drv);
+       destroy_workqueue(kpsmoused_wq);
 }
 
 module_init(psmouse_init);
index 7c4192bd1279c62e16d621942b0855384e7f3f91..4d9107fba6a10e8da641a3b5e5630924b66fe110 100644 (file)
@@ -7,7 +7,7 @@
 #define PSMOUSE_CMD_GETINFO    0x03e9
 #define PSMOUSE_CMD_SETSTREAM  0x00ea
 #define PSMOUSE_CMD_SETPOLL    0x00f0
-#define PSMOUSE_CMD_POLL       0x03eb
+#define PSMOUSE_CMD_POLL       0x00eb  /* caller sets number of bytes to receive */
 #define PSMOUSE_CMD_GETID      0x02f2
 #define PSMOUSE_CMD_SETRATE    0x10f3
 #define PSMOUSE_CMD_ENABLE     0x00f4
@@ -23,6 +23,7 @@
 enum psmouse_state {
        PSMOUSE_IGNORE,
        PSMOUSE_INITIALIZING,
+       PSMOUSE_RESYNCING,
        PSMOUSE_CMD_MODE,
        PSMOUSE_ACTIVATED,
 };
@@ -38,15 +39,19 @@ struct psmouse {
        void *private;
        struct input_dev *dev;
        struct ps2dev ps2dev;
+       struct work_struct resync_work;
        char *vendor;
        char *name;
        unsigned char packet[8];
+       unsigned char badbyte;
        unsigned char pktcnt;
        unsigned char pktsize;
        unsigned char type;
+       unsigned char acks_disable_command;
        unsigned int model;
        unsigned long last;
        unsigned long out_of_sync;
+       unsigned long num_resyncs;
        enum psmouse_state state;
        char devname[64];
        char phys[32];
@@ -54,6 +59,7 @@ struct psmouse {
        unsigned int rate;
        unsigned int resolution;
        unsigned int resetafter;
+       unsigned int resync_time;
        unsigned int smartscroll;       /* Logitech only */
 
        psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
@@ -62,6 +68,7 @@ struct psmouse {
 
        int (*reconnect)(struct psmouse *psmouse);
        void (*disconnect)(struct psmouse *psmouse);
+       int (*poll)(struct psmouse *psmouse);
 
        void (*pt_activate)(struct psmouse *psmouse);
        void (*pt_deactivate)(struct psmouse *psmouse);
index 97cdfd6acaca039e06d89e3073a72c8b712d70dd..2051bec2c394b896700612590749ac7b31da9de2 100644 (file)
@@ -652,6 +652,8 @@ int synaptics_init(struct psmouse *psmouse)
        psmouse->disconnect = synaptics_disconnect;
        psmouse->reconnect = synaptics_reconnect;
        psmouse->pktsize = 6;
+       /* Synaptics can usually stay in sync without extra help */
+       psmouse->resync_time = 0;
 
        if (SYN_CAP_PASS_THROUGH(priv->capabilities))
                synaptics_pt_create(psmouse);
index 2d2f9fb3adede436e1e965be059f8f6210e77092..a4c6f352272390af0d2d8b740d53a1bb8cd2668d 100644 (file)
@@ -173,6 +173,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "PC-MM20 Series"),
                },
        },
+       {
+               .ident = "Sony Vaio FS-115b",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
+               },
+       },
        { }
 };
 
index 8e530cc970e198c62f535d4d3361e98189cd400b..2f76813c3a645c7d3d6a9e797df4525f19c6ac3d 100644 (file)
@@ -59,9 +59,7 @@ static DECLARE_MUTEX(serio_sem);
 
 static LIST_HEAD(serio_list);
 
-static struct bus_type serio_bus = {
-       .name = "serio",
-};
+static struct bus_type serio_bus;
 
 static void serio_add_port(struct serio *serio);
 static void serio_destroy_port(struct serio *serio);
@@ -750,11 +748,15 @@ static int serio_driver_remove(struct device *dev)
        return 0;
 }
 
+static struct bus_type serio_bus = {
+       .name = "serio",
+       .probe = serio_driver_probe,
+       .remove = serio_driver_remove,
+};
+
 void __serio_register_driver(struct serio_driver *drv, struct module *owner)
 {
        drv->driver.bus = &serio_bus;
-       drv->driver.probe = serio_driver_probe;
-       drv->driver.remove = serio_driver_remove;
 
        serio_queue_event(drv, owner, SERIO_REGISTER_DRIVER);
 }
index 21d55ed4b88a69e08881a4b03f1ef9dbf20548d2..2c674023a6acd5f71d2fe742a7a9d2428ae180b1 100644 (file)
@@ -11,6 +11,19 @@ menuconfig INPUT_TOUCHSCREEN
 
 if INPUT_TOUCHSCREEN
 
+config TOUCHSCREEN_ADS7846
+       tristate "ADS 7846 based touchscreens"
+       depends on SPI_MASTER
+       help
+         Say Y here if you have a touchscreen interface using the
+         ADS7846 controller, and your board-specific initialization
+         code includes that in its table of SPI devices.
+
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called ads7846.
+
 config TOUCHSCREEN_BITSY
        tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
        depends on SA1100_BITSY
index 6842869c9a263d570b0ace2c53ace0e461cac9dc..5e5557c43121a128243412074d689c8340a5f2fd 100644 (file)
@@ -4,6 +4,7 @@
 
 # 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
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
new file mode 100644 (file)
index 0000000..dd8c6a9
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ * ADS7846 based touchscreen and sensor driver
+ *
+ * Copyright (c) 2005 David Brownell
+ *
+ * Using code from:
+ *  - corgi_ts.c
+ *     Copyright (C) 2004-2005 Richard Purdie
+ *  - omap_ts.[hc], ads7846.h, ts_osk.c
+ *     Copyright (C) 2002 MontaVista Software
+ *     Copyright (C) 2004 Texas Instruments
+ *     Copyright (C) 2005 Dirk Behme
+ *
+ *  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/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#ifdef CONFIG_ARM
+#include <asm/mach-types.h>
+#ifdef CONFIG_ARCH_OMAP
+#include <asm/arch/gpio.h>
+#endif
+
+#else
+#define        set_irq_type(irq,type)  do{}while(0)
+#endif
+
+
+/*
+ * This code has been lightly tested on an ads7846.
+ * Support for ads7843 and ads7845 has only been stubbed in.
+ *
+ * Not yet done:  investigate the values reported.  Are x/y/pressure
+ * event values sane enough for X11?  How accurate are the temperature
+ * and voltage readings?  (System-specific calibration should support
+ * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.)
+ *
+ * app note sbaa036 talks in more detail about accurate sampling...
+ * that ought to help in situations like LCDs inducing noise (which
+ * can also be helped by using synch signals) and more generally.
+ */
+
+#define        TS_POLL_PERIOD  msecs_to_jiffies(10)
+
+struct ts_event {
+       /* For portability, we can't read 12 bit values using SPI (which
+        * would make the controller deliver them as native byteorder u16
+        * with msbs zeroed).  Instead, we read them as two 8-byte values,
+        * which need byteswapping then range adjustment.
+        */
+       __be16 x;
+       __be16 y;
+       __be16 z1, z2;
+};
+
+struct ads7846 {
+       struct input_dev        input;
+       char                    phys[32];
+
+       struct spi_device       *spi;
+       u16                     model;
+       u16                     vref_delay_usecs;
+       u16                     x_plate_ohms;
+
+       struct ts_event         tc;
+
+       struct spi_transfer     xfer[8];
+       struct spi_message      msg;
+
+       spinlock_t              lock;
+       struct timer_list       timer;          /* P: lock */
+       unsigned                pendown:1;      /* P: lock */
+       unsigned                pending:1;      /* P: lock */
+// FIXME remove "irq_disabled"
+       unsigned                irq_disabled:1; /* P: lock */
+};
+
+/* leave chip selected when we're done, for quicker re-select? */
+#if    0
+#define        CS_CHANGE(xfer) ((xfer).cs_change = 1)
+#else
+#define        CS_CHANGE(xfer) ((xfer).cs_change = 0)
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+/* The ADS7846 has touchscreen and other sensors.
+ * Earlier ads784x chips are somewhat compatible.
+ */
+#define        ADS_START               (1 << 7)
+#define        ADS_A2A1A0_d_y          (1 << 4)        /* differential */
+#define        ADS_A2A1A0_d_z1         (3 << 4)        /* differential */
+#define        ADS_A2A1A0_d_z2         (4 << 4)        /* differential */
+#define        ADS_A2A1A0_d_x          (5 << 4)        /* differential */
+#define        ADS_A2A1A0_temp0        (0 << 4)        /* non-differential */
+#define        ADS_A2A1A0_vbatt        (2 << 4)        /* non-differential */
+#define        ADS_A2A1A0_vaux         (6 << 4)        /* non-differential */
+#define        ADS_A2A1A0_temp1        (7 << 4)        /* non-differential */
+#define        ADS_8_BIT               (1 << 3)
+#define        ADS_12_BIT              (0 << 3)
+#define        ADS_SER                 (1 << 2)        /* non-differential */
+#define        ADS_DFR                 (0 << 2)        /* differential */
+#define        ADS_PD10_PDOWN          (0 << 0)        /* lowpower mode + penirq */
+#define        ADS_PD10_ADC_ON         (1 << 0)        /* ADC on */
+#define        ADS_PD10_REF_ON         (2 << 0)        /* vREF on + penirq */
+#define        ADS_PD10_ALL_ON         (3 << 0)        /* ADC + vREF on */
+
+#define        MAX_12BIT       ((1<<12)-1)
+
+/* leave ADC powered up (disables penirq) between differential samples */
+#define        READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
+       | ADS_12_BIT | ADS_DFR)
+
+static const u8        read_y  = READ_12BIT_DFR(y)  | ADS_PD10_ADC_ON;
+static const u8        read_z1 = READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON;
+static const u8        read_z2 = READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON;
+static const u8        read_x  = READ_12BIT_DFR(x)  | ADS_PD10_PDOWN;  /* LAST */
+
+/* single-ended samples need to first power up reference voltage;
+ * we leave both ADC and VREF powered
+ */
+#define        READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
+       | ADS_12_BIT | ADS_SER)
+
+static const u8        ref_on = READ_12BIT_DFR(x) | ADS_PD10_ALL_ON;
+static const u8        ref_off = READ_12BIT_DFR(y) | ADS_PD10_PDOWN;
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Non-touchscreen sensors only use single-ended conversions.
+ */
+
+struct ser_req {
+       u8                      command;
+       u16                     scratch;
+       __be16                  sample;
+       struct spi_message      msg;
+       struct spi_transfer     xfer[6];
+};
+
+static int ads7846_read12_ser(struct device *dev, unsigned command)
+{
+       struct spi_device       *spi = to_spi_device(dev);
+       struct ads7846          *ts = dev_get_drvdata(dev);
+       struct ser_req          *req = kzalloc(sizeof *req, SLAB_KERNEL);
+       int                     status;
+       int                     sample;
+       int                     i;
+
+       if (!req)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&req->msg.transfers);
+
+       /* activate reference, so it has time to settle; */
+       req->xfer[0].tx_buf = &ref_on;
+       req->xfer[0].len = 1;
+       req->xfer[1].rx_buf = &req->scratch;
+       req->xfer[1].len = 2;
+
+       /*
+        * for external VREF, 0 usec (and assume it's always on);
+        * for 1uF, use 800 usec;
+        * no cap, 100 usec.
+        */
+       req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+
+       /* take sample */
+       req->command = (u8) command;
+       req->xfer[2].tx_buf = &req->command;
+       req->xfer[2].len = 1;
+       req->xfer[3].rx_buf = &req->sample;
+       req->xfer[3].len = 2;
+
+       /* REVISIT:  take a few more samples, and compare ... */
+
+       /* turn off reference */
+       req->xfer[4].tx_buf = &ref_off;
+       req->xfer[4].len = 1;
+       req->xfer[5].rx_buf = &req->scratch;
+       req->xfer[5].len = 2;
+
+       CS_CHANGE(req->xfer[5]);
+
+       /* group all the transfers together, so we can't interfere with
+        * reading touchscreen state; disable penirq while sampling
+        */
+       for (i = 0; i < 6; i++)
+               spi_message_add_tail(&req->xfer[i], &req->msg);
+
+       disable_irq(spi->irq);
+       status = spi_sync(spi, &req->msg);
+       enable_irq(spi->irq);
+
+       if (req->msg.status)
+               status = req->msg.status;
+       sample = be16_to_cpu(req->sample);
+       sample = sample >> 4;
+       kfree(req);
+
+       return status ? status : sample;
+}
+
+#define SHOW(name) static ssize_t \
+name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       ssize_t v = ads7846_read12_ser(dev, \
+                       READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+       if (v < 0) \
+               return v; \
+       return sprintf(buf, "%u\n", (unsigned) v); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
+
+SHOW(temp0)
+SHOW(temp1)
+SHOW(vaux)
+SHOW(vbatt)
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * PENIRQ only kicks the timer.  The timer only reissues the SPI transfer,
+ * to retrieve touchscreen status.
+ *
+ * The SPI transfer completion callback does the real work.  It reports
+ * touchscreen events and reactivates the timer (or IRQ) as appropriate.
+ */
+
+static void ads7846_rx(void *ads)
+{
+       struct ads7846  *ts = ads;
+       unsigned        Rt;
+       unsigned        sync = 0;
+       u16             x, y, z1, z2;
+       unsigned long   flags;
+
+       /* adjust:  12 bit samples (left aligned), built from
+        * two 8 bit values writen msb-first.
+        */
+       x = be16_to_cpu(ts->tc.x) >> 4;
+       y = be16_to_cpu(ts->tc.y) >> 4;
+       z1 = be16_to_cpu(ts->tc.z1) >> 4;
+       z2 = be16_to_cpu(ts->tc.z2) >> 4;
+
+       /* range filtering */
+       if (x == MAX_12BIT)
+               x = 0;
+
+       if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) {
+               /* compute touch pressure resistance using equation #2 */
+               Rt = z2;
+               Rt -= z1;
+               Rt *= x;
+               Rt *= ts->x_plate_ohms;
+               Rt /= z1;
+               Rt = (Rt + 2047) >> 12;
+       } else
+               Rt = 0;
+
+       /* NOTE:  "pendown" is inferred from pressure; we don't rely on
+        * being able to check nPENIRQ status, or "friendly" trigger modes
+        * (both-edges is much better than just-falling or low-level).
+        *
+        * REVISIT:  some boards may require reading nPENIRQ; it's
+        * needed on 7843.  and 7845 reads pressure differently...
+        *
+        * REVISIT:  the touchscreen might not be connected; this code
+        * won't notice that, even if nPENIRQ never fires ...
+        */
+       if (!ts->pendown && Rt != 0) {
+               input_report_key(&ts->input, BTN_TOUCH, 1);
+               sync = 1;
+       } else if (ts->pendown && Rt == 0) {
+               input_report_key(&ts->input, BTN_TOUCH, 0);
+               sync = 1;
+       }
+
+       if (Rt) {
+               input_report_abs(&ts->input, ABS_X, x);
+               input_report_abs(&ts->input, ABS_Y, y);
+               input_report_abs(&ts->input, ABS_PRESSURE, Rt);
+               sync = 1;
+       }
+       if (sync)
+               input_sync(&ts->input);
+
+#ifdef VERBOSE
+       if (Rt || ts->pendown)
+               pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
+                       x, y, Rt, Rt ? "" : " UP");
+#endif
+
+       /* don't retrigger while we're suspended */
+       spin_lock_irqsave(&ts->lock, flags);
+
+       ts->pendown = (Rt != 0);
+       ts->pending = 0;
+
+       if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) {
+               if (ts->pendown)
+                       mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+               else if (ts->irq_disabled) {
+                       ts->irq_disabled = 0;
+                       enable_irq(ts->spi->irq);
+               }
+       }
+
+       spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static void ads7846_timer(unsigned long handle)
+{
+       struct ads7846  *ts = (void *)handle;
+       int             status = 0;
+       unsigned long   flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+       if (!ts->pending) {
+               ts->pending = 1;
+               if (!ts->irq_disabled) {
+                       ts->irq_disabled = 1;
+                       disable_irq(ts->spi->irq);
+               }
+               status = spi_async(ts->spi, &ts->msg);
+               if (status)
+                       dev_err(&ts->spi->dev, "spi_async --> %d\n",
+                                       status);
+       }
+       spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
+{
+       ads7846_timer((unsigned long) handle);
+       return IRQ_HANDLED;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int
+ads7846_suspend(struct spi_device *spi, pm_message_t message)
+{
+       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+       unsigned long   flags;
+
+       spin_lock_irqsave(&ts->lock, flags);
+
+       spi->dev.power.power_state = message;
+
+       /* are we waiting for IRQ, or polling? */
+       if (!ts->pendown) {
+               if (!ts->irq_disabled) {
+                       ts->irq_disabled = 1;
+                       disable_irq(ts->spi->irq);
+               }
+       } else {
+               /* polling; force a final SPI completion;
+                * that will clean things up neatly
+                */
+               if (!ts->pending)
+                       mod_timer(&ts->timer, jiffies);
+
+               while (ts->pendown || ts->pending) {
+                       spin_unlock_irqrestore(&ts->lock, flags);
+                       udelay(10);
+                       spin_lock_irqsave(&ts->lock, flags);
+               }
+       }
+
+       /* we know the chip's in lowpower mode since we always
+        * leave it that way after every request
+        */
+
+       spin_unlock_irqrestore(&ts->lock, flags);
+       return 0;
+}
+
+static int ads7846_resume(struct spi_device *spi)
+{
+       struct ads7846 *ts = dev_get_drvdata(&spi->dev);
+
+       ts->irq_disabled = 0;
+       enable_irq(ts->spi->irq);
+       spi->dev.power.power_state = PMSG_ON;
+       return 0;
+}
+
+static int __devinit ads7846_probe(struct spi_device *spi)
+{
+       struct ads7846                  *ts;
+       struct ads7846_platform_data    *pdata = spi->dev.platform_data;
+       struct spi_transfer             *x;
+       int                             i;
+
+       if (!spi->irq) {
+               dev_dbg(&spi->dev, "no IRQ?\n");
+               return -ENODEV;
+       }
+
+       if (!pdata) {
+               dev_dbg(&spi->dev, "no platform data?\n");
+               return -ENODEV;
+       }
+
+       /* don't exceed max specified sample rate */
+       if (spi->max_speed_hz > (125000 * 16)) {
+               dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+                               (spi->max_speed_hz/16)/1000);
+               return -EINVAL;
+       }
+
+       /* We'd set the wordsize to 12 bits ... except that some controllers
+        * will then treat the 8 bit command words as 12 bits (and drop the
+        * four MSBs of the 12 bit result).  Result: inputs must be shifted
+        * to discard the four garbage LSBs.
+        */
+
+       if (!(ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL)))
+               return -ENOMEM;
+
+       dev_set_drvdata(&spi->dev, ts);
+
+       ts->spi = spi;
+       spi->dev.power.power_state = PMSG_ON;
+
+       init_timer(&ts->timer);
+       ts->timer.data = (unsigned long) ts;
+       ts->timer.function = ads7846_timer;
+
+       ts->model = pdata->model ? : 7846;
+       ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
+       ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
+
+       init_input_dev(&ts->input);
+
+       ts->input.dev = &spi->dev;
+       ts->input.name = "ADS784x Touchscreen";
+       snprintf(ts->phys, sizeof ts->phys, "%s/input0", spi->dev.bus_id);
+       ts->input.phys = ts->phys;
+
+       ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+       input_set_abs_params(&ts->input, ABS_X,
+                       pdata->x_min ? : 0,
+                       pdata->x_max ? : MAX_12BIT,
+                       0, 0);
+       input_set_abs_params(&ts->input, ABS_Y,
+                       pdata->y_min ? : 0,
+                       pdata->y_max ? : MAX_12BIT,
+                       0, 0);
+       input_set_abs_params(&ts->input, ABS_PRESSURE,
+                       pdata->pressure_min, pdata->pressure_max, 0, 0);
+
+       input_register_device(&ts->input);
+
+       /* set up the transfers to read touchscreen state; this assumes we
+        * use formula #2 for pressure, not #3.
+        */
+       x = ts->xfer;
+
+       /* y- still on; turn on only y+ (and ADC) */
+       x->tx_buf = &read_y;
+       x->len = 1;
+       x++;
+       x->rx_buf = &ts->tc.y;
+       x->len = 2;
+       x++;
+
+       /* turn y+ off, x- on; we'll use formula #2 */
+       if (ts->model == 7846) {
+               x->tx_buf = &read_z1;
+               x->len = 1;
+               x++;
+               x->rx_buf = &ts->tc.z1;
+               x->len = 2;
+               x++;
+
+               x->tx_buf = &read_z2;
+               x->len = 1;
+               x++;
+               x->rx_buf = &ts->tc.z2;
+               x->len = 2;
+               x++;
+       }
+
+       /* turn y- off, x+ on, then leave in lowpower */
+       x->tx_buf = &read_x;
+       x->len = 1;
+       x++;
+       x->rx_buf = &ts->tc.x;
+       x->len = 2;
+       x++;
+
+       CS_CHANGE(x[-1]);
+
+       for (i = 0; i < x - ts->xfer; i++)
+               spi_message_add_tail(&ts->xfer[i], &ts->msg);
+       ts->msg.complete = ads7846_rx;
+       ts->msg.context = ts;
+
+       if (request_irq(spi->irq, ads7846_irq, SA_SAMPLE_RANDOM,
+                               spi->dev.bus_id, ts)) {
+               dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+               input_unregister_device(&ts->input);
+               kfree(ts);
+               return -EBUSY;
+       }
+       set_irq_type(spi->irq, IRQT_FALLING);
+
+       dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
+
+       /* take a first sample, leaving nPENIRQ active; avoid
+        * the touchscreen, in case it's not connected.
+        */
+       (void) ads7846_read12_ser(&spi->dev,
+                         READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+
+       /* ads7843/7845 don't have temperature sensors, and
+        * use the other sensors a bit differently too
+        */
+       if (ts->model == 7846) {
+               device_create_file(&spi->dev, &dev_attr_temp0);
+               device_create_file(&spi->dev, &dev_attr_temp1);
+       }
+       if (ts->model != 7845)
+               device_create_file(&spi->dev, &dev_attr_vbatt);
+       device_create_file(&spi->dev, &dev_attr_vaux);
+
+       return 0;
+}
+
+static int __devexit ads7846_remove(struct spi_device *spi)
+{
+       struct ads7846          *ts = dev_get_drvdata(&spi->dev);
+
+       ads7846_suspend(spi, PMSG_SUSPEND);
+       free_irq(ts->spi->irq, ts);
+       if (ts->irq_disabled)
+               enable_irq(ts->spi->irq);
+
+       if (ts->model == 7846) {
+               device_remove_file(&spi->dev, &dev_attr_temp0);
+               device_remove_file(&spi->dev, &dev_attr_temp1);
+       }
+       if (ts->model != 7845)
+               device_remove_file(&spi->dev, &dev_attr_vbatt);
+       device_remove_file(&spi->dev, &dev_attr_vaux);
+
+       input_unregister_device(&ts->input);
+       kfree(ts);
+
+       dev_dbg(&spi->dev, "unregistered touchscreen\n");
+       return 0;
+}
+
+static struct spi_driver ads7846_driver = {
+       .driver = {
+               .name   = "ads7846",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ads7846_probe,
+       .remove         = __devexit_p(ads7846_remove),
+       .suspend        = ads7846_suspend,
+       .resume         = ads7846_resume,
+};
+
+static int __init ads7846_init(void)
+{
+       /* grr, board-specific init should stay out of drivers!! */
+
+#ifdef CONFIG_ARCH_OMAP
+       if (machine_is_omap_osk()) {
+               /* GPIO4 = PENIRQ; GPIO6 = BUSY */
+               omap_request_gpio(4);
+               omap_set_gpio_direction(4, 1);
+               omap_request_gpio(6);
+               omap_set_gpio_direction(6, 1);
+       }
+       // also TI 1510 Innovator, bitbanging through FPGA
+       // also Nokia 770
+       // also Palm Tungsten T2
+#endif
+
+       // PXA:
+       // also Dell Axim X50
+       // also HP iPaq H191x/H192x/H415x/H435x
+       // also Intel Lubbock (additional to UCB1400; as temperature sensor)
+       // also Sharp Zaurus C7xx, C8xx (corgi/sheperd/husky)
+
+       // Atmel at91sam9261-EK uses ads7843
+
+       // also various AMD Au1x00 devel boards
+
+       return spi_register_driver(&ads7846_driver);
+}
+module_init(ads7846_init);
+
+static void __exit ads7846_exit(void)
+{
+       spi_unregister_driver(&ads7846_driver);
+
+#ifdef CONFIG_ARCH_OMAP
+       if (machine_is_omap_osk()) {
+               omap_free_gpio(4);
+               omap_free_gpio(6);
+       }
+#endif
+
+}
+module_exit(ads7846_exit);
+
+MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
+MODULE_LICENSE("GPL");
index 5d8ee7368f7b79828abc89ec32b9e64724417bc9..4abe5ff10e723d0ce01920538de86bd0ab800843 100644 (file)
@@ -358,7 +358,7 @@ hdlc_fill_fifo(struct BCState *bcs)
        }
 }
 
-static inline void
+static void
 HDLC_irq(struct BCState *bcs, u_int stat) {
        int len;
        struct sk_buff *skb;
index b62d6b30b72b861711090ef5d7fd2b591b615828..b0ff1cc97d7cb418bac3d3289fb0fe2b879904c4 100644 (file)
@@ -476,7 +476,7 @@ Memhscx_fill_fifo(struct BCState *bcs)
        }
 }
 
-static inline void
+static void
 Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 {
        u_char r;
index 5fe9d42d03a3f2709c14a44bdd9fc5e890351635..7b1ad5e4ecdac10a046d573761aeae11f00bdd65 100644 (file)
@@ -119,7 +119,7 @@ hscx_fill_fifo(struct BCState *bcs)
        }
 }
 
-static inline void
+static void
 hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
 {
        u_char r;
@@ -221,7 +221,7 @@ hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx)
        }
 }
 
-static inline void
+static void
 hscx_int_main(struct IsdnCardState *cs, u_char val)
 {
 
index 08563400e4fdc6725fe3d52a6a1f89c7cf41000d..1f201af15a0fd781575060409165ba328f562598 100644 (file)
@@ -110,7 +110,7 @@ jade_fill_fifo(struct BCState *bcs)
 }
 
 
-static inline void
+static void
 jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
 {
        u_char r;
index cf6a6f2248ac421aee3fc1bb2629710c280ef33c..314fc0830d9004d4a32998e6bb563c5719357822 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 
 struct preg {
        unsigned char r;
@@ -88,24 +89,26 @@ int macio_probe(void)
 int macio_init(void)
 {
        struct device_node *adbs;
+       struct resource r;
 
        adbs = find_compatible_devices("adb", "chrp,adb0");
        if (adbs == 0)
                return -ENXIO;
 
 #if 0
-       { int i;
+       { int i = 0;
 
        printk("macio_adb_init: node = %p, addrs =", adbs->node);
-       for (i = 0; i < adbs->n_addrs; ++i)
-               printk(" %x(%x)", adbs->addrs[i].address, adbs->addrs[i].size);
+       while(!of_address_to_resource(adbs, i, &r))
+               printk(" %x(%x)", r.start, r.end - r.start);
        printk(", intrs =");
        for (i = 0; i < adbs->n_intrs; ++i)
                printk(" %x", adbs->intrs[i].line);
        printk("\n"); }
 #endif
-       
-       adb = ioremap(adbs->addrs->address, sizeof(struct adb_regs));
+       if (of_address_to_resource(adbs, 0, &r))
+               return -ENXIO;
+       adb = ioremap(r.start, sizeof(struct adb_regs));
 
        out_8(&adb->ctrl.r, 0);
        out_8(&adb->intr.r, 0);
index 2a545ceb523b05cfb57fdf20b8c79e1ca1f5ca2e..ed6d3174d66050f1ca3358909469770682111243 100644 (file)
@@ -211,6 +211,9 @@ struct bus_type macio_bus_type = {
        .name   = "macio",
        .match  = macio_bus_match,
        .uevent = macio_uevent,
+       .probe  = macio_device_probe,
+       .remove = macio_device_remove,
+       .shutdown = macio_device_shutdown,
        .suspend        = macio_device_suspend,
        .resume = macio_device_resume,
        .dev_attrs = macio_dev_attrs,
@@ -528,9 +531,6 @@ int macio_register_driver(struct macio_driver *drv)
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &macio_bus_type;
-       drv->driver.probe = macio_device_probe;
-       drv->driver.remove = macio_device_remove;
-       drv->driver.shutdown = macio_device_shutdown;
 
        /* register with core */
        count = driver_register(&drv->driver);
index 76a189ceb5291a755c1c74d3279541269a7b2774..eae4473eadde2a359a7e00e05b8bf4a5387140cc 100644 (file)
@@ -200,7 +200,7 @@ out:
 /* if page is completely empty, put it back on the free list, or dealloc it */
 /* if page was hijacked, unmark the flag so it might get alloced next time */
 /* Note: lock should be held when calling this */
-static inline void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
+static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
 {
        char *ptr;
 
index a601a427885cb0e97afa15449b89c9347e2b3b7a..e7a650f9ca076599ed185a8f734ea54e790e30a4 100644 (file)
@@ -228,7 +228,7 @@ static struct crypt_iv_operations crypt_iv_essiv_ops = {
 };
 
 
-static inline int
+static int
 crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
                           struct scatterlist *in, unsigned int length,
                           int write, sector_t sector)
index 561bda5011e00e07f2d0a80e8aa5d147f81cd023..1235135b384bea5ac1e82129926e30c85d36bd9f 100644 (file)
@@ -598,7 +598,7 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
 /*
  * Always use UUID for lookups if it's present, otherwise use name or dev.
  */
-static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
+static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
 {
        if (*param->uuid)
                return __get_uuid_cell(param->uuid);
@@ -608,7 +608,7 @@ static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
                return dm_get_mdptr(huge_decode_dev(param->dev));
 }
 
-static inline struct mapped_device *find_device(struct dm_ioctl *param)
+static struct mapped_device *find_device(struct dm_ioctl *param)
 {
        struct hash_cell *hc;
        struct mapped_device *md = NULL;
index 4b9dd8fb1e5c223e8629ff4cb7ddb6764dd08fe9..87727d84dbbac9bdd013aab25e78122976b23980 100644 (file)
@@ -691,7 +691,7 @@ static void copy_callback(int read_err, unsigned int write_err, void *context)
 /*
  * Dispatches the copy operation to kcopyd.
  */
-static inline void start_copy(struct pending_exception *pe)
+static void start_copy(struct pending_exception *pe)
 {
        struct dm_snapshot *s = pe->snap;
        struct io_region src, dest;
index 097d1e540090bcf50b703be7d83a7c7f76a49d97..8c16359f8b0189c5a77d6eb19106ceb21231c0ce 100644 (file)
@@ -293,7 +293,7 @@ struct dm_table *dm_get_table(struct mapped_device *md)
  * Decrements the number of outstanding ios that a bio has been
  * cloned into, completing the original io if necc.
  */
-static inline void dec_pending(struct dm_io *io, int error)
+static void dec_pending(struct dm_io *io, int error)
 {
        if (error)
                io->error = error;
index a06ff91f27e2e6bb3af330e170faebdd79e6a9ce..d39f584cd8b3000d048f3f83007a9dc3ec672a1e 100644 (file)
@@ -176,7 +176,7 @@ static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
        }
 }
 
-static inline void free_r1bio(r1bio_t *r1_bio)
+static void free_r1bio(r1bio_t *r1_bio)
 {
        conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
@@ -190,7 +190,7 @@ static inline void free_r1bio(r1bio_t *r1_bio)
        mempool_free(r1_bio, conf->r1bio_pool);
 }
 
-static inline void put_buf(r1bio_t *r1_bio)
+static void put_buf(r1bio_t *r1_bio)
 {
        conf_t *conf = mddev_to_conf(r1_bio->mddev);
        int i;
index 9e658e519a27c378c63cb8b82025e450b818b52b..9130d051b474d64c4816644be4bc89d3b397f37a 100644 (file)
@@ -176,7 +176,7 @@ static void put_all_bios(conf_t *conf, r10bio_t *r10_bio)
        }
 }
 
-static inline void free_r10bio(r10bio_t *r10_bio)
+static void free_r10bio(r10bio_t *r10_bio)
 {
        conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
@@ -190,7 +190,7 @@ static inline void free_r10bio(r10bio_t *r10_bio)
        mempool_free(r10_bio, conf->r10bio_pool);
 }
 
-static inline void put_buf(r10bio_t *r10_bio)
+static void put_buf(r10bio_t *r10_bio)
 {
        conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
index 54f4a9847e38dc9665cac4a0364f2a7e17bd9c35..25976bfb6f9c19b841aa432dff67c0c24a425435 100644 (file)
@@ -69,7 +69,7 @@
 
 static void print_raid5_conf (raid5_conf_t *conf);
 
-static inline void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
+static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
 {
        if (atomic_dec_and_test(&sh->count)) {
                if (!list_empty(&sh->lru))
@@ -118,7 +118,7 @@ static inline void remove_hash(struct stripe_head *sh)
        hlist_del_init(&sh->hash);
 }
 
-static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
+static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
 {
        struct hlist_head *hp = stripe_hash(conf, sh->sector);
 
@@ -178,7 +178,7 @@ static int grow_buffers(struct stripe_head *sh, int num)
 
 static void raid5_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
        raid5_conf_t *conf = sh->raid_conf;
        int disks = conf->raid_disks, i;
@@ -1415,7 +1415,7 @@ static void handle_stripe(struct stripe_head *sh)
        }
 }
 
-static inline void raid5_activate_delayed(raid5_conf_t *conf)
+static void raid5_activate_delayed(raid5_conf_t *conf)
 {
        if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
                while (!list_empty(&conf->delayed_list)) {
@@ -1431,7 +1431,7 @@ static inline void raid5_activate_delayed(raid5_conf_t *conf)
        }
 }
 
-static inline void activate_bit_delay(raid5_conf_t *conf)
+static void activate_bit_delay(raid5_conf_t *conf)
 {
        /* device_lock is held */
        struct list_head head;
index 8c823d686a60a75de478b601de56bfb871278ff7..f618a53b98bee235cca1160e4d08b16bd955ff0c 100644 (file)
@@ -88,7 +88,7 @@ static inline int raid6_next_disk(int disk, int raid_disks)
 
 static void print_raid6_conf (raid6_conf_t *conf);
 
-static inline void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
+static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
 {
        if (atomic_dec_and_test(&sh->count)) {
                if (!list_empty(&sh->lru))
@@ -197,7 +197,7 @@ static int grow_buffers(struct stripe_head *sh, int num)
 
 static void raid6_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
+static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
        raid6_conf_t *conf = sh->raid_conf;
        int disks = conf->raid_disks, i;
@@ -1577,7 +1577,7 @@ static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
        }
 }
 
-static inline void raid6_activate_delayed(raid6_conf_t *conf)
+static void raid6_activate_delayed(raid6_conf_t *conf)
 {
        if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
                while (!list_empty(&conf->delayed_list)) {
@@ -1593,7 +1593,7 @@ static inline void raid6_activate_delayed(raid6_conf_t *conf)
        }
 }
 
-static inline void activate_bit_delay(raid6_conf_t *conf)
+static void activate_bit_delay(raid6_conf_t *conf)
 {
        /* device_lock is held */
        struct list_head head;
index f65f64b00ff342aa5c0140198e13be55db99ff2b..44fcbe77c8f95b24e5d5d137e490c22144685800 100644 (file)
@@ -779,9 +779,8 @@ static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
        return 0;
 }
 
-static int dvb_bt8xx_probe(struct device *dev)
+static int dvb_bt8xx_probe(struct bttv_sub_device *sub)
 {
-       struct bttv_sub_device *sub = to_bttv_sub_dev(dev);
        struct dvb_bt8xx_card *card;
        struct pci_dev* bttv_pci_dev;
        int ret;
@@ -890,13 +889,13 @@ static int dvb_bt8xx_probe(struct device *dev)
                return ret;
        }
 
-       dev_set_drvdata(dev, card);
+       dev_set_drvdata(&sub->dev, card);
        return 0;
 }
 
-static int dvb_bt8xx_remove(struct device *dev)
+static int dvb_bt8xx_remove(struct bttv_sub_device *sub)
 {
-       struct dvb_bt8xx_card *card = dev_get_drvdata(dev);
+       struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
 
        dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
 
@@ -919,14 +918,14 @@ static int dvb_bt8xx_remove(struct device *dev)
 static struct bttv_sub_driver driver = {
        .drv = {
                .name           = "dvb-bt8xx",
-               .probe          = dvb_bt8xx_probe,
-               .remove         = dvb_bt8xx_remove,
-               /* FIXME:
-                * .shutdown    = dvb_bt8xx_shutdown,
-                * .suspend     = dvb_bt8xx_suspend,
-                * .resume      = dvb_bt8xx_resume,
-                */
        },
+       .probe          = dvb_bt8xx_probe,
+       .remove         = dvb_bt8xx_remove,
+       /* FIXME:
+        * .shutdown    = dvb_bt8xx_shutdown,
+        * .suspend     = dvb_bt8xx_suspend,
+        * .resume      = dvb_bt8xx_resume,
+        */
 };
 
 static int __init dvb_bt8xx_init(void)
index d64accc17b0ef7854438845f6b4cb49096988e89..c4d5e2b70c28e12c28761b09713e5d669cb3fcdc 100644 (file)
@@ -47,9 +47,29 @@ static int bttv_sub_bus_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
+static int bttv_sub_probe(struct device *dev)
+{
+       struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+       struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+       return sub->probe ? sub->probe(sdev) : -ENODEV;
+}
+
+static int bttv_sub_remove(struct device *dev)
+{
+       struct bttv_sub_device *sdev = to_bttv_sub_dev(dev);
+       struct bttv_sub_driver *sub = to_bttv_sub_drv(dev->driver);
+
+       if (sub->remove)
+               sub->remove(sdev);
+       return 0;
+}
+
 struct bus_type bttv_sub_bus_type = {
-       .name  = "bttv-sub",
-       .match = &bttv_sub_bus_match,
+       .name   = "bttv-sub",
+       .match  = &bttv_sub_bus_match,
+       .probe  = bttv_sub_probe,
+       .remove = bttv_sub_remove,
 };
 EXPORT_SYMBOL(bttv_sub_bus_type);
 
index e370d74f2a1b1f50a17aaa0b4d8b75f6cdb7ab8e..9908c8e0c951636e68c1121f2e2b4a7262194020 100644 (file)
@@ -365,6 +365,8 @@ struct bttv_sub_device {
 struct bttv_sub_driver {
        struct device_driver   drv;
        char                   wanted[BUS_ID_SIZE];
+       int                    (*probe)(struct bttv_sub_device *sub);
+       void                   (*remove)(struct bttv_sub_device *sub);
        void                   (*gpio_irq)(struct bttv_sub_device *sub);
 };
 #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
index 8713c4d0dccae3ad23ad7e448f9eaf176cb6a90f..fad9ea0ae4f22d73e9a8f70f82c152523b45f6d4 100644 (file)
@@ -93,7 +93,7 @@ struct tvp5150 {
        int sat;
 };
 
-static inline int tvp5150_read(struct i2c_client *c, unsigned char addr)
+static int tvp5150_read(struct i2c_client *c, unsigned char addr)
 {
        unsigned char buffer[1];
        int rc;
index ea3288661a3457d65a49b2d841514c18674760e8..246e67cd8b51c1710586c28c91e63adbe9d058e4 100644 (file)
@@ -995,7 +995,7 @@ test_interrupts (struct zoran *zr)
 static int __devinit
 zr36057_init (struct zoran *zr)
 {
-       unsigned long mem;
+       u32 *mem;
        void *vdev;
        unsigned mem_needed;
        int j;
@@ -1058,10 +1058,10 @@ zr36057_init (struct zoran *zr)
                        "%s: zr36057_init() - kmalloc (STAT_COM) failed\n",
                        ZR_DEVNAME(zr));
                kfree(vdev);
-               kfree((void *)mem);
+               kfree(mem);
                return -ENOMEM;
        }
-       zr->stat_com = (u32 *) mem;
+       zr->stat_com = mem;
        for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
                zr->stat_com[j] = 1;    /* mark as unavailable to zr36057 */
        }
index 1883d22cffeb100a73bf3ea1479722aad93f0b98..e67cf15e9c3961af697067c4007e78ffd359da4b 100644 (file)
@@ -23,6 +23,7 @@ config FUSION_FC
        tristate "Fusion MPT ScsiHost drivers for FC"
        depends on PCI && SCSI
        select FUSION
+       select SCSI_FC_ATTRS
        ---help---
          SCSI HOST support for a Fiber Channel host adapters.
 
index b61e3d175070f6cefec9ce17f6eaf8ae3f8b8b54..02cdc840a06b0ab3c6c2d114c18699ac8b2430ad 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    mpi.h Version:  01.05.08
+ *    mpi.h Version:  01.05.10
  *
  *  Version History
  *  ---------------
@@ -74,6 +74,8 @@
  *  06-24-05  01.05.08  Added function codes for SCSI IO 32 and
  *                      TargetAssistExtended requests.
  *                      Added EEDP IOCStatus codes.
+ *  08-03-05  01.05.09  Bumped MPI_HEADER_VERSION_UNIT.
+ *  08-30-05  01.05.10  Added 2 new IOCStatus codes for Target.
  *  --------------------------------------------------------------------------
  */
 
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x0A)
+#define MPI_HEADER_VERSION_UNIT             (0x0C)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
@@ -711,6 +713,8 @@ typedef struct _MSG_DEFAULT_REPLY
 #define MPI_IOCSTATUS_TARGET_DATA_OFFSET_ERROR   (0x006D)
 #define MPI_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E)
 #define MPI_IOCSTATUS_TARGET_IU_TOO_SHORT        (0x006F)
+#define MPI_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT     (0x0070)
+#define MPI_IOCSTATUS_TARGET_NAK_RECEIVED        (0x0071)
 
 /****************************************************************************/
 /*  Additional FCP target values (obsolete)                                 */
@@ -745,7 +749,7 @@ typedef struct _MSG_DEFAULT_REPLY
 #define MPI_IOCSTATUS_LAN_CANCELED              (0x0087)
 
 /****************************************************************************/
-/*  Serial Attached SCSI values                                                              */
+/*  Serial Attached SCSI values                                             */
 /****************************************************************************/
 
 #define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED    (0x0090)
index d8339896f7343c60732c3f0f5f6c92bf8391373f..b1becec27e1bf021af9fde7bfb4d08d9b19d34b7 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    mpi_cnfg.h Version:  01.05.09
+ *    mpi_cnfg.h Version:  01.05.11
  *
  *  Version History
  *  ---------------
  *                      Added OwnerDevHandle and Flags field to SAS PHY Page 0.
  *                      Added IOC GPIO Flags define to SAS Enclosure Page 0.
  *                      Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT.
+ *  08-03-05  01.05.10  Removed ISDataScrubRate and ISResyncRate from
+ *                      Manufacturing Page 4.
+ *                      Added MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE bit.
+ *                      Added NumDevsPerEnclosure field to SAS IO Unit page 2.
+ *                      Added MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP
+ *                      define.
+ *                      Added EnclosureHandle field to SAS Expander page 0.
+ *                      Removed redundant NumTableEntriesProg field from SAS
+ *                      Expander Page 1.
+ *  08-30-05  01.05.11  Added DeviceID for FC949E and changed the DeviceID for
+ *                      SAS1078.
+ *                      Added more defines for Manufacturing Page 4 Flags field.
+ *                      Added more defines for IOCSettings and added
+ *                      ExpanderSpinup field to Bios Page 1.
+ *                      Added postpone SATA Init bit to SAS IO Unit Page 1
+ *                      ControlFlags.
+ *                      Changed LogEntry format for Log Page 0.
  *  --------------------------------------------------------------------------
  */
 
@@ -494,7 +511,7 @@ typedef struct _MSG_CONFIG_REPLY
 #define MPI_MANUFACTPAGE_DEVICEID_FC929X            (0x0626)
 #define MPI_MANUFACTPAGE_DEVICEID_FC939X            (0x0642)
 #define MPI_MANUFACTPAGE_DEVICEID_FC949X            (0x0640)
-#define MPI_MANUFACTPAGE_DEVICEID_FC949ES           (0x0646)
+#define MPI_MANUFACTPAGE_DEVICEID_FC949E            (0x0646)
 /* SCSI */
 #define MPI_MANUFACTPAGE_DEVID_53C1030              (0x0030)
 #define MPI_MANUFACTPAGE_DEVID_53C1030ZC            (0x0031)
@@ -510,7 +527,7 @@ typedef struct _MSG_CONFIG_REPLY
 #define MPI_MANUFACTPAGE_DEVID_SAS1066E             (0x005A)
 #define MPI_MANUFACTPAGE_DEVID_SAS1068              (0x0054)
 #define MPI_MANUFACTPAGE_DEVID_SAS1068E             (0x0058)
-#define MPI_MANUFACTPAGE_DEVID_SAS1078              (0x0060)
+#define MPI_MANUFACTPAGE_DEVID_SAS1078              (0x0062)
 
 
 typedef struct _CONFIG_PAGE_MANUFACTURING_0
@@ -602,9 +619,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
     U32                             IMVolumeSettings;   /* 50h */
     U32                             Reserved3;          /* 54h */
     U32                             Reserved4;          /* 58h */
-    U8                              ISDataScrubRate;    /* 5Ch */
-    U8                              ISResyncRate;       /* 5Dh */
-    U16                             Reserved5;          /* 5Eh */
+    U32                             Reserved5;          /* 5Ch */
     U8                              IMEDataScrubRate;   /* 60h */
     U8                              IMEResyncRate;      /* 61h */
     U16                             Reserved6;          /* 62h */
@@ -616,9 +631,14 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
 } CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
   ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
 
-#define MPI_MANUFACTURING4_PAGEVERSION                  (0x02)
+#define MPI_MANUFACTURING4_PAGEVERSION                  (0x03)
 
 /* defines for the Flags field */
+#define MPI_MANPAGE4_IME_DISABLE                        (0x20)
+#define MPI_MANPAGE4_IM_DISABLE                         (0x10)
+#define MPI_MANPAGE4_IS_DISABLE                         (0x08)
+#define MPI_MANPAGE4_IR_MODEPAGE8_DISABLE               (0x04)
+#define MPI_MANPAGE4_IM_RESYNC_CACHE_ENABLE             (0x02)
 #define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA                 (0x01)
 
 
@@ -669,7 +689,7 @@ typedef struct _CONFIG_PAGE_IO_UNIT_1
 } CONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1,
   IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t;
 
-#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x01)
+#define MPI_IOUNITPAGE1_PAGEVERSION                     (0x02)
 
 /* IO Unit Page 1 Flags defines */
 #define MPI_IOUNITPAGE1_MULTI_FUNCTION                  (0x00000000)
@@ -681,7 +701,7 @@ typedef struct _CONFIG_PAGE_IO_UNIT_1
 #define MPI_IOUNITPAGE1_DISABLE_IR                      (0x00000040)
 #define MPI_IOUNITPAGE1_FORCE_32                        (0x00000080)
 #define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE        (0x00000100)
-
+#define MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE        (0x00000200)
 
 typedef struct _MPI_ADAPTER_INFO
 {
@@ -968,7 +988,8 @@ typedef struct _CONFIG_PAGE_BIOS_1
     U32                     Reserved1;                  /* 0Ch */
     U32                     DeviceSettings;             /* 10h */
     U16                     NumberOfDevices;            /* 14h */
-    U16                     Reserved2;                  /* 16h */
+    U8                      ExpanderSpinup;             /* 16h */
+    U8                      Reserved2;                  /* 17h */
     U16                     IOTimeoutBlockDevicesNonRM; /* 18h */
     U16                     IOTimeoutSequential;        /* 1Ah */
     U16                     IOTimeoutOther;             /* 1Ch */
@@ -976,7 +997,7 @@ typedef struct _CONFIG_PAGE_BIOS_1
 } CONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1,
   BIOSPage1_t, MPI_POINTER pBIOSPage1_t;
 
-#define MPI_BIOSPAGE1_PAGEVERSION                       (0x02)
+#define MPI_BIOSPAGE1_PAGEVERSION                       (0x03)
 
 /* values for the BiosOptions field */
 #define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE                (0x00000400)
@@ -985,8 +1006,15 @@ typedef struct _CONFIG_PAGE_BIOS_1
 #define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS              (0x00000001)
 
 /* values for the IOCSettings field */
+#define MPI_BIOSPAGE1_IOCSET_MASK_INITIAL_SPINUP_DELAY  (0x0F000000)
+#define MPI_BIOSPAGE1_IOCSET_SHIFT_INITIAL_SPINUP_DELAY (24)
+
 #define MPI_BIOSPAGE1_IOCSET_MASK_PORT_ENABLE_DELAY     (0x00F00000)
 #define MPI_BIOSPAGE1_IOCSET_SHIFT_PORT_ENABLE_DELAY    (20)
+
+#define MPI_BIOSPAGE1_IOCSET_AUTO_PORT_ENABLE           (0x00080000)
+#define MPI_BIOSPAGE1_IOCSET_DIRECT_ATTACH_SPINUP_MODE  (0x00040000)
+
 #define MPI_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE       (0x00030000)
 #define MPI_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT        (0x00000000)
 #define MPI_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT           (0x00010000)
@@ -1016,6 +1044,11 @@ typedef struct _CONFIG_PAGE_BIOS_1
 #define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN         (0x00000002)
 #define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN          (0x00000001)
 
+/* defines for the ExpanderSpinup field */
+#define MPI_BIOSPAGE1_EXPSPINUP_MASK_MAX_TARGET         (0xF0)
+#define MPI_BIOSPAGE1_EXPSPINUP_SHIFT_MAX_TARGET        (4)
+#define MPI_BIOSPAGE1_EXPSPINUP_MASK_DELAY              (0x0F)
+
 typedef struct _MPI_BOOT_DEVICE_ADAPTER_ORDER
 {
     U32         Reserved1;                              /* 00h */
@@ -1233,13 +1266,13 @@ typedef struct _CONFIG_PAGE_SCSI_PORT_0
 
 #define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD     (8)
 #define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap)      \
-    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MIN_SYNC_PERIOD) \
+    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK) \
     >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD          \
     )
 #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK      (0x00FF0000)
 #define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET     (16)
 #define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap)      \
-    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MAX_SYNC_OFFSET) \
+    (  ((Cap) & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK) \
     >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET          \
     )
 #define MPI_SCSIPORTPAGE0_CAP_IDP                       (0x08000000)
@@ -2370,47 +2403,48 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
 } CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1,
   SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t;
 
-#define MPI_SASIOUNITPAGE1_PAGEVERSION      (0x04)
+#define MPI_SASIOUNITPAGE1_PAGEVERSION      (0x05)
 
 /* values for SAS IO Unit Page 1 ControlFlags */
-#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST        (0x8000)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX            (0x4000)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX            (0x2000)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE        (0x1000)
-#define MPI_SAS_IOUNIT1_CONTROL_DISABLE_SAS_HASH        (0x0800)
-
-#define MPI_SAS_IOUNIT1_CONTROL_MASK_DEV_SUPPORT        (0x0600)
-#define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT       (9)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH        (0x00)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT         (0x01)
-#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT        (0x02)
-
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED     (0x0040)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED       (0x0020)
-#define MPI_SAS_IOUNIT1_CONTROL_SATA_FUA_REQUIRED       (0x0010)
-#define MPI_SAS_IOUNIT1_CONTROL_PHY_ENABLE_ORDER_HIGH   (0x0008)
-#define MPI_SAS_IOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL     (0x0004)
-#define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY     (0x0002)
-#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION       (0x0001)
+#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST            (0x8000)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX                (0x4000)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX                (0x2000)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE            (0x1000)
+#define MPI_SAS_IOUNIT1_CONTROL_DISABLE_SAS_HASH            (0x0800)
+
+#define MPI_SAS_IOUNIT1_CONTROL_MASK_DEV_SUPPORT            (0x0600)
+#define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT           (9)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH            (0x00)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT             (0x01)
+#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT            (0x02)
+
+#define MPI_SAS_IOUNIT1_CONTROL_POSTPONE_SATA_INIT          (0x0100)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED     (0x0080)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED         (0x0040)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED           (0x0020)
+#define MPI_SAS_IOUNIT1_CONTROL_SATA_FUA_REQUIRED           (0x0010)
+#define MPI_SAS_IOUNIT1_CONTROL_PHY_ENABLE_ORDER_HIGH       (0x0008)
+#define MPI_SAS_IOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL         (0x0004)
+#define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY         (0x0002)
+#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION           (0x0001)
 
 /* values for SAS IO Unit Page 1 PortFlags */
-#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM     (0x00)
-#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM     (0x04)
-#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG     (0x01)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM         (0x00)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM         (0x04)
+#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG         (0x01)
 
 /* values for SAS IO Unit Page 0 PhyFlags */
-#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE           (0x04)
-#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT             (0x02)
-#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT             (0x01)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE               (0x04)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT                 (0x02)
+#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT                 (0x01)
 
 /* values for SAS IO Unit Page 0 MaxMinLinkRate */
-#define MPI_SAS_IOUNIT1_MAX_RATE_MASK                   (0xF0)
-#define MPI_SAS_IOUNIT1_MAX_RATE_1_5                    (0x80)
-#define MPI_SAS_IOUNIT1_MAX_RATE_3_0                    (0x90)
-#define MPI_SAS_IOUNIT1_MIN_RATE_MASK                   (0x0F)
-#define MPI_SAS_IOUNIT1_MIN_RATE_1_5                    (0x08)
-#define MPI_SAS_IOUNIT1_MIN_RATE_3_0                    (0x09)
+#define MPI_SAS_IOUNIT1_MAX_RATE_MASK                       (0xF0)
+#define MPI_SAS_IOUNIT1_MAX_RATE_1_5                        (0x80)
+#define MPI_SAS_IOUNIT1_MAX_RATE_3_0                        (0x90)
+#define MPI_SAS_IOUNIT1_MIN_RATE_MASK                       (0x0F)
+#define MPI_SAS_IOUNIT1_MIN_RATE_1_5                        (0x08)
+#define MPI_SAS_IOUNIT1_MIN_RATE_3_0                        (0x09)
 
 /* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
 
@@ -2418,16 +2452,18 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
 typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2
 {
     CONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
-    U32                                 Reserved1;              /* 08h */
+    U8                                  NumDevsPerEnclosure;    /* 08h */
+    U8                                  Reserved1;              /* 09h */
+    U16                                 Reserved2;              /* 0Ah */
     U16                                 MaxPersistentIDs;       /* 0Ch */
     U16                                 NumPersistentIDsUsed;   /* 0Eh */
     U8                                  Status;                 /* 10h */
     U8                                  Flags;                  /* 11h */
-    U16                                 MaxNumPhysicalMappedIDs;/* 12h */              /* 12h */
+    U16                                 MaxNumPhysicalMappedIDs;/* 12h */
 } CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2,
   SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t;
 
-#define MPI_SASIOUNITPAGE2_PAGEVERSION      (0x04)
+#define MPI_SASIOUNITPAGE2_PAGEVERSION      (0x05)
 
 /* values for SAS IO Unit Page 2 Status field */
 #define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02)
@@ -2441,6 +2477,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2
 #define MPI_SAS_IOUNIT2_FLAGS_NO_PHYS_MAP                   (0x00)
 #define MPI_SAS_IOUNIT2_FLAGS_DIRECT_ATTACH_PHYS_MAP        (0x01)
 #define MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP       (0x02)
+#define MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP        (0x07)
 
 #define MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT         (0x10)
 #define MPI_SAS_IOUNIT2_FLAGS_DA_STARTING_SLOT              (0x20)
@@ -2473,7 +2510,7 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER_0
     CONFIG_EXTENDED_PAGE_HEADER         Header;                 /* 00h */
     U8                                  PhysicalPort;           /* 08h */
     U8                                  Reserved1;              /* 09h */
-    U16                                 Reserved2;              /* 0Ah */
+    U16                                 EnclosureHandle;        /* 0Ah */
     U64                                 SASAddress;             /* 0Ch */
     U32                                 DiscoveryStatus;        /* 14h */
     U16                                 DevHandle;              /* 18h */
@@ -2487,7 +2524,7 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER_0
 } CONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0,
   SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t;
 
-#define MPI_SASEXPANDER0_PAGEVERSION        (0x02)
+#define MPI_SASEXPANDER0_PAGEVERSION        (0x03)
 
 /* values for SAS Expander Page 0 DiscoveryStatus field */
 #define MPI_SAS_EXPANDER0_DS_LOOP_DETECTED              (0x00000001)
@@ -2527,9 +2564,9 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER_1
     U8                          NegotiatedLinkRate;     /* 1Fh */
     U8                          PhyIdentifier;          /* 20h */
     U8                          AttachedPhyIdentifier;  /* 21h */
-    U8                          NumTableEntriesProg;    /* 22h */
+    U8                          Reserved3;              /* 22h */
     U8                          DiscoveryInfo;          /* 23h */
-    U32                         Reserved3;              /* 24h */
+    U32                         Reserved4;              /* 24h */
 } CONFIG_PAGE_SAS_EXPANDER_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_1,
   SasExpanderPage1_t, MPI_POINTER pSasExpanderPage1_t;
 
@@ -2766,16 +2803,15 @@ typedef struct _CONFIG_PAGE_SAS_ENCLOSURE_0
 #define MPI_LOG_0_NUM_LOG_ENTRIES        (1)
 #endif
 
-#define MPI_LOG_0_LOG_DATA_LENGTH        (20)
+#define MPI_LOG_0_LOG_DATA_LENGTH        (0x1C)
 
 typedef struct _MPI_LOG_0_ENTRY
 {
-    U64         WWID;                               /* 00h */
-    U32         TimeStamp;                          /* 08h */
-    U32         Reserved1;                          /* 0Ch */
-    U16         LogSequence;                        /* 10h */
-    U16         LogEntryQualifier;                  /* 12h */
-    U8          LogData[MPI_LOG_0_LOG_DATA_LENGTH]; /* 14h */
+    U32         TimeStamp;                          /* 00h */
+    U32         Reserved1;                          /* 04h */
+    U16         LogSequence;                        /* 08h */
+    U16         LogEntryQualifier;                  /* 0Ah */
+    U8          LogData[MPI_LOG_0_LOG_DATA_LENGTH]; /* 0Ch */
 } MPI_LOG_0_ENTRY, MPI_POINTER PTR_MPI_LOG_0_ENTRY,
   MpiLog0Entry_t, MPI_POINTER pMpiLog0Entry_t;
 
@@ -2794,7 +2830,7 @@ typedef struct _CONFIG_PAGE_LOG_0
 } CONFIG_PAGE_LOG_0, MPI_POINTER PTR_CONFIG_PAGE_LOG_0,
   LogPage0_t, MPI_POINTER pLogPage0_t;
 
-#define MPI_LOG_0_PAGEVERSION               (0x00)
+#define MPI_LOG_0_PAGEVERSION               (0x01)
 
 
 #endif
index 1a30ef16adb4d58911967f5cf585c0c7306cbf94..4a5f8dd1d7666711ccc0f29ad1395e88e30a7a4a 100644 (file)
@@ -6,25 +6,25 @@
  Copyright (c) 2000-2005 LSI Logic Corporation.
 
  ---------------------------------------
- Header Set Release Version:    01.05.10
- Header Set Release Date:       03-11-05
+ Header Set Release Version:    01.05.12
+ Header Set Release Date:       08-30-05
  ---------------------------------------
 
  Filename               Current version     Prior version
  ----------             ---------------     -------------
- mpi.h                  01.05.08            01.05.07
- mpi_ioc.h              01.05.09            01.05.08
- mpi_cnfg.h             01.05.09            01.05.08
- mpi_init.h             01.05.05            01.05.04
- mpi_targ.h             01.05.05            01.05.04
+ mpi.h                  01.05.10            01.05.09
+ mpi_ioc.h              01.05.10            01.05.09
+ mpi_cnfg.h             01.05.11            01.05.10
+ mpi_init.h             01.05.06            01.05.06
+ mpi_targ.h             01.05.05            01.05.05
  mpi_fc.h               01.05.01            01.05.01
  mpi_lan.h              01.05.01            01.05.01
  mpi_raid.h             01.05.02            01.05.02
  mpi_tool.h             01.05.03            01.05.03
  mpi_inb.h              01.05.01            01.05.01
- mpi_sas.h              01.05.01            01.05.01
- mpi_type.h             01.05.01            01.05.01
- mpi_history.txt        01.05.09            01.05.09
+ mpi_sas.h              01.05.02            01.05.01
+ mpi_type.h             01.05.02            01.05.01
+ mpi_history.txt        01.05.12            01.05.11
 
 
  *  Date      Version   Description
@@ -91,6 +91,8 @@ mpi.h
  *  06-24-05  01.05.08  Added function codes for SCSI IO 32 and
  *                      TargetAssistExtended requests.
  *                      Added EEDP IOCStatus codes.
+ *  08-03-05  01.05.09  Bumped MPI_HEADER_VERSION_UNIT.
+ *  08-30-05  01.05.10  Added 2 new IOCStatus codes for Target.
  *  --------------------------------------------------------------------------
 
 mpi_ioc.h
@@ -164,6 +166,10 @@ mpi_ioc.h
  *                      Removed IOCFacts Reply EEDP Capability bit.
  *  06-24-05  01.05.09  Added 5 new IOCFacts Reply IOCCapabilities bits.
  *                      Added Max SATA Targets to SAS Discovery Error event.
+ *  08-30-05  01.05.10  Added 4 new events and their event data structures.
+ *                      Added new ReasonCode value for SAS Device Status Change
+ *                      event.
+ *                      Added new family code for FC949E.
  *  --------------------------------------------------------------------------
 
 mpi_cnfg.h
@@ -402,6 +408,23 @@ mpi_cnfg.h
  *                      Added OwnerDevHandle and Flags field to SAS PHY Page 0.
  *                      Added IOC GPIO Flags define to SAS Enclosure Page 0.
  *                      Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT.
+ *  08-03-05  01.05.10  Removed ISDataScrubRate and ISResyncRate from
+ *                      Manufacturing Page 4.
+ *                      Added MPI_IOUNITPAGE1_SATA_WRITE_CACHE_DISABLE bit.
+ *                      Added NumDevsPerEnclosure field to SAS IO Unit page 2.
+ *                      Added MPI_SAS_IOUNIT2_FLAGS_HOST_ASSIGNED_PHYS_MAP
+ *                      define.
+ *                      Added EnclosureHandle field to SAS Expander page 0.
+ *                      Removed redundant NumTableEntriesProg field from SAS
+ *                      Expander Page 1.
+ *  08-30-05  01.05.11  Added DeviceID for FC949E and changed the DeviceID for
+ *                      SAS1078.
+ *                      Added more defines for Manufacturing Page 4 Flags field.
+ *                      Added more defines for IOCSettings and added
+ *                      ExpanderSpinup field to Bios Page 1.
+ *                      Added postpone SATA Init bit to SAS IO Unit Page 1
+ *                      ControlFlags.
+ *                      Changed LogEntry format for Log Page 0.
  *  --------------------------------------------------------------------------
 
 mpi_init.h
@@ -442,6 +465,8 @@ mpi_init.h
  *                      addressing.
  *  06-24-05  01.05.05  Added SCSI IO 32 structures and defines.
  *                      Added four new defines for SEP SlotStatus.
+ *  08-03-05  01.05.06  Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
+ *                      unique in the first 32 characters.
  *  --------------------------------------------------------------------------
 
 mpi_targ.h
@@ -582,6 +607,9 @@ mpi_inb.h
 
 mpi_sas.h
  *  08-19-04  01.05.01  Original release.
+ *  08-30-05  01.05.02  Added DeviceInfo bit for SEP.
+ *                      Added PrimFlags and Primitive field to SAS IO Unit
+ *                      Control request, and added a new operation code.
  *  --------------------------------------------------------------------------
 
 mpi_type.h
@@ -592,24 +620,25 @@ mpi_type.h
  *  08-08-01  01.02.01  Original release for v1.2 work.
  *  05-11-04  01.03.01  Original release for MPI v1.3.
  *  08-19-04  01.05.01  Original release for MPI v1.5.
+ *  08-30-05  01.05.02  Added PowerPC option to #ifdef's.
  *  --------------------------------------------------------------------------
 
 mpi_history.txt         Parts list history
 
-Filename    01.05.10  01.05.09
-----------  --------  --------
-mpi.h       01.05.08  01.05.07
-mpi_ioc.h   01.05.09  01.05.08
-mpi_cnfg.h  01.05.09  01.05.08
-mpi_init.h  01.05.05  01.05.04
-mpi_targ.h  01.05.05  01.05.04
-mpi_fc.h    01.05.01  01.05.01
-mpi_lan.h   01.05.01  01.05.01
-mpi_raid.h  01.05.02  01.05.02
-mpi_tool.h  01.05.03  01.05.03
-mpi_inb.h   01.05.01  01.05.01
-mpi_sas.h   01.05.01  01.05.01
-mpi_type.h  01.05.01  01.05.01
+Filename    01.05.12  01.05.11  01.05.10  01.05.09
+----------  --------  --------  --------  --------
+mpi.h       01.05.10  01.05.09  01.05.08  01.05.07
+mpi_ioc.h   01.05.10  01.05.09  01.05.09  01.05.08
+mpi_cnfg.h  01.05.11  01.05.10  01.05.09  01.05.08
+mpi_init.h  01.05.06  01.05.06  01.05.05  01.05.04
+mpi_targ.h  01.05.05  01.05.05  01.05.05  01.05.04
+mpi_fc.h    01.05.01  01.05.01  01.05.01  01.05.01
+mpi_lan.h   01.05.01  01.05.01  01.05.01  01.05.01
+mpi_raid.h  01.05.02  01.05.02  01.05.02  01.05.02
+mpi_tool.h  01.05.03  01.05.03  01.05.03  01.05.03
+mpi_inb.h   01.05.01  01.05.01  01.05.01  01.05.01
+mpi_sas.h   01.05.02  01.05.01  01.05.01  01.05.01
+mpi_type.h  01.05.02  01.05.01  01.05.01  01.05.01
 
 Filename    01.05.08   01.05.07   01.05.06   01.05.05   01.05.04   01.05.03
 ----------  --------   --------   --------   --------   --------   --------
index d5af75afbd94a8545b163012be4aef243dc7f36d..68941f459ca33e3ae41ca0f26b886ecdea6c464d 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI initiator mode messages and structures
  *  Creation Date:  June 8, 2000
  *
- *    mpi_init.h Version:  01.05.05
+ *    mpi_init.h Version:  01.05.06
  *
  *  Version History
  *  ---------------
@@ -50,6 +50,8 @@
  *                      addressing.
  *  06-24-05  01.05.05  Added SCSI IO 32 structures and defines.
  *                      Added four new defines for SEP SlotStatus.
+ *  08-03-05  01.05.06  Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
+ *                      unique in the first 32 characters.
  *  --------------------------------------------------------------------------
  */
 
@@ -290,8 +292,8 @@ typedef struct _MSG_SCSI_IO32_REQUEST
 
 /* SCSI IO 32 MsgFlags bits */
 #define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH                (0x01)
-#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_32             (0x00)
-#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_64             (0x01)
+#define MPI_SCSIIO32_MSGFLGS_32_SENSE_WIDTH             (0x00)
+#define MPI_SCSIIO32_MSGFLGS_64_SENSE_WIDTH             (0x01)
 
 #define MPI_SCSIIO32_MSGFLGS_SENSE_LOCATION             (0x02)
 #define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_HOST             (0x00)
index 93b70e2b426623813c290bca3315ac36705e1f24..2c5f43fa7c73d742522b1cc00e0163731f398fa1 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  August 11, 2000
  *
- *    mpi_ioc.h Version:  01.05.09
+ *    mpi_ioc.h Version:  01.05.10
  *
  *  Version History
  *  ---------------
  *                      Removed IOCFacts Reply EEDP Capability bit.
  *  06-24-05  01.05.09  Added 5 new IOCFacts Reply IOCCapabilities bits.
  *                      Added Max SATA Targets to SAS Discovery Error event.
+ *  08-30-05  01.05.10  Added 4 new events and their event data structures.
+ *                      Added new ReasonCode value for SAS Device Status Change
+ *                      event.
+ *                      Added new family code for FC949E.
  *  --------------------------------------------------------------------------
  */
 
@@ -464,6 +468,10 @@ typedef struct _MSG_EVENT_ACK_REPLY
 #define MPI_EVENT_PERSISTENT_TABLE_FULL     (0x00000011)
 #define MPI_EVENT_SAS_PHY_LINK_STATUS       (0x00000012)
 #define MPI_EVENT_SAS_DISCOVERY_ERROR       (0x00000013)
+#define MPI_EVENT_IR_RESYNC_UPDATE          (0x00000014)
+#define MPI_EVENT_IR2                       (0x00000015)
+#define MPI_EVENT_SAS_DISCOVERY             (0x00000016)
+#define MPI_EVENT_LOG_ENTRY_ADDED           (0x00000021)
 
 /* AckRequired field values */
 
@@ -480,6 +488,29 @@ typedef struct _EVENT_DATA_EVENT_CHANGE
 } EVENT_DATA_EVENT_CHANGE, MPI_POINTER PTR_EVENT_DATA_EVENT_CHANGE,
   EventDataEventChange_t, MPI_POINTER pEventDataEventChange_t;
 
+/* LogEntryAdded Event data */
+
+/* this structure matches MPI_LOG_0_ENTRY in mpi_cnfg.h */
+#define MPI_EVENT_DATA_LOG_ENTRY_DATA_LENGTH    (0x1C)
+typedef struct _EVENT_DATA_LOG_ENTRY
+{
+    U32         TimeStamp;                          /* 00h */
+    U32         Reserved1;                          /* 04h */
+    U16         LogSequence;                        /* 08h */
+    U16         LogEntryQualifier;                  /* 0Ah */
+    U8          LogData[MPI_EVENT_DATA_LOG_ENTRY_DATA_LENGTH]; /* 0Ch */
+} EVENT_DATA_LOG_ENTRY, MPI_POINTER PTR_EVENT_DATA_LOG_ENTRY,
+  MpiEventDataLogEntry_t, MPI_POINTER pMpiEventDataLogEntry_t;
+
+typedef struct _EVENT_DATA_LOG_ENTRY_ADDED
+{
+    U16                     LogSequence;            /* 00h */
+    U16                     Reserved1;              /* 02h */
+    U32                     Reserved2;              /* 04h */
+    EVENT_DATA_LOG_ENTRY    LogEntry;               /* 08h */
+} EVENT_DATA_LOG_ENTRY_ADDED, MPI_POINTER PTR_EVENT_DATA_LOG_ENTRY_ADDED,
+  MpiEventDataLogEntryAdded_t, MPI_POINTER pMpiEventDataLogEntryAdded_t;
+
 /* SCSI Event data for Port, Bus and Device forms */
 
 typedef struct _EVENT_DATA_SCSI
@@ -538,6 +569,7 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
 #define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA            (0x05)
 #define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED      (0x06)
 #define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED           (0x07)
+#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
 
 
 /* SCSI Event data for Queue Full event */
@@ -579,6 +611,79 @@ typedef struct _EVENT_DATA_RAID
 #define MPI_EVENT_RAID_RC_SMART_DATA                    (0x0A)
 #define MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED        (0x0B)
 
+
+/* MPI Integrated RAID Resync Update Event data */
+
+typedef struct _MPI_EVENT_DATA_IR_RESYNC_UPDATE
+{
+    U8                      VolumeID;                   /* 00h */
+    U8                      VolumeBus;                  /* 01h */
+    U8                      ResyncComplete;             /* 02h */
+    U8                      Reserved1;                  /* 03h */
+    U32                     Reserved2;                  /* 04h */
+} MPI_EVENT_DATA_IR_RESYNC_UPDATE,
+  MPI_POINTER PTR_MPI_EVENT_DATA_IR_RESYNC_UPDATE,
+  MpiEventDataIrResyncUpdate_t, MPI_POINTER pMpiEventDataIrResyncUpdate_t;
+
+/* MPI IR2 Event data */
+
+/* MPI_LD_STATE or MPI_PD_STATE */
+typedef struct _IR2_STATE_CHANGED
+{
+    U16                 PreviousState;  /* 00h */
+    U16                 NewState;       /* 02h */
+} IR2_STATE_CHANGED, MPI_POINTER PTR_IR2_STATE_CHANGED;
+
+typedef struct _IR2_PD_INFO
+{
+    U16                 DeviceHandle;           /* 00h */
+    U8                  TruncEnclosureHandle;   /* 02h */
+    U8                  TruncatedSlot;          /* 03h */
+} IR2_PD_INFO, MPI_POINTER PTR_IR2_PD_INFO;
+
+typedef union _MPI_IR2_RC_EVENT_DATA
+{
+    IR2_STATE_CHANGED   StateChanged;
+    U32                 Lba;
+    IR2_PD_INFO         PdInfo;
+} MPI_IR2_RC_EVENT_DATA, MPI_POINTER PTR_MPI_IR2_RC_EVENT_DATA;
+
+typedef struct _MPI_EVENT_DATA_IR2
+{
+    U8                      TargetID;             /* 00h */
+    U8                      Bus;                  /* 01h */
+    U8                      ReasonCode;           /* 02h */
+    U8                      PhysDiskNum;          /* 03h */
+    MPI_IR2_RC_EVENT_DATA   IR2EventData;         /* 04h */
+} MPI_EVENT_DATA_IR2, MPI_POINTER PTR_MPI_EVENT_DATA_IR2,
+  MpiEventDataIR2_t, MPI_POINTER pMpiEventDataIR2_t;
+
+/* MPI IR2 Event data ReasonCode values */
+#define MPI_EVENT_IR2_RC_LD_STATE_CHANGED           (0x01)
+#define MPI_EVENT_IR2_RC_PD_STATE_CHANGED           (0x02)
+#define MPI_EVENT_IR2_RC_BAD_BLOCK_TABLE_FULL       (0x03)
+#define MPI_EVENT_IR2_RC_PD_INSERTED                (0x04)
+#define MPI_EVENT_IR2_RC_PD_REMOVED                 (0x05)
+#define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED       (0x06)
+#define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR       (0x07)
+
+/* defines for logical disk states */
+#define MPI_LD_STATE_OPTIMAL                        (0x00)
+#define MPI_LD_STATE_DEGRADED                       (0x01)
+#define MPI_LD_STATE_FAILED                         (0x02)
+#define MPI_LD_STATE_MISSING                        (0x03)
+#define MPI_LD_STATE_OFFLINE                        (0x04)
+
+/* defines for physical disk states */
+#define MPI_PD_STATE_ONLINE                         (0x00)
+#define MPI_PD_STATE_MISSING                        (0x01)
+#define MPI_PD_STATE_NOT_COMPATIBLE                 (0x02)
+#define MPI_PD_STATE_FAILED                         (0x03)
+#define MPI_PD_STATE_INITIALIZING                   (0x04)
+#define MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST        (0x05)
+#define MPI_PD_STATE_FAILED_AT_HOST_REQUEST         (0x06)
+#define MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON     (0xFF)
+
 /* MPI Link Status Change Event data */
 
 typedef struct _EVENT_DATA_LINK_STATUS
@@ -660,6 +765,20 @@ typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS
 #define MPI_EVENT_SAS_PLS_LR_RATE_1_5                       (0x08)
 #define MPI_EVENT_SAS_PLS_LR_RATE_3_0                       (0x09)
 
+/* SAS Discovery Event data */
+
+typedef struct _EVENT_DATA_SAS_DISCOVERY
+{
+    U32                     DiscoveryStatus;            /* 00h */
+    U32                     Reserved1;                  /* 04h */
+} EVENT_DATA_SAS_DISCOVERY, MPI_POINTER PTR_EVENT_DATA_SAS_DISCOVERY,
+  EventDataSasDiscovery_t, MPI_POINTER pEventDataSasDiscovery_t;
+
+#define MPI_EVENT_SAS_DSCVRY_COMPLETE                       (0x00000000)
+#define MPI_EVENT_SAS_DSCVRY_IN_PROGRESS                    (0x00000001)
+#define MPI_EVENT_SAS_DSCVRY_PHY_BITS_MASK                  (0xFFFF0000)
+#define MPI_EVENT_SAS_DSCVRY_PHY_BITS_SHIFT                 (16)
+
 /* SAS Discovery Errror Event data */
 
 typedef struct _EVENT_DATA_DISCOVERY_ERROR
@@ -869,6 +988,7 @@ typedef struct _MPI_FW_HEADER
 #define MPI_FW_HEADER_PID_FAMILY_919XL_FC       (0x0003) /* 919XL and 929XL */
 #define MPI_FW_HEADER_PID_FAMILY_939X_FC        (0x0004) /* 939X and 949X   */
 #define MPI_FW_HEADER_PID_FAMILY_959_FC         (0x0005)
+#define MPI_FW_HEADER_PID_FAMILY_949E_FC        (0x0006)
 /* SAS */
 #define MPI_FW_HEADER_PID_FAMILY_1064_SAS       (0x0001)
 #define MPI_FW_HEADER_PID_FAMILY_1068_SAS       (0x0002)
diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h
new file mode 100644 (file)
index 0000000..dc98d46
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ *
+ *  NAME:           fc_log.h
+ *  SUMMARY:        MPI IocLogInfo definitions for the SYMFC9xx chips
+ *  DESCRIPTION:    Contains the enumerated list of values that may be returned
+ *                  in the IOCLogInfo field of a MPI Default Reply Message.
+ *
+ *  CREATION DATE:  6/02/2000
+ *  ID:             $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $
+ */
+
+
+/*
+ * MpiIocLogInfo_t enum
+ *
+ * These 32 bit values are used in the IOCLogInfo field of the MPI reply
+ * messages.
+ * The value is 0xabcccccc where
+ *          a = The type of log info as per the MPI spec. Since these codes are
+ *              all for Fibre Channel this value will always be 2.
+ *          b = Specifies a subclass of the firmware where
+ *                  0 = FCP Initiator
+ *                  1 = FCP Target
+ *                  2 = LAN
+ *                  3 = MPI Message Layer
+ *                  4 = FC Link
+ *                  5 = Context Manager
+ *                  6 = Invalid Field Offset
+ *                  7 = State Change Info
+ *                  all others are reserved for future use
+ *          c = A specific value within the subclass.
+ *
+ * NOTE: Any new values should be added to the end of each subclass so that the
+ *       codes remain consistent across firmware releases.
+ */
+typedef enum _MpiIocLogInfoFc
+{
+    MPI_IOCLOGINFO_FC_INIT_BASE                     = 0x20000000,
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME   = 0x20000003, /* Bad Rx Frame, bad end of frame primative */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN           = 0x20000004, /* Bad Rx Frame, overrun */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER           = 0x20000005, /* Other errors caught by IOC which require retries */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD       = 0x20000006, /* Main processor could not initialize sub-processor */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN         = 0x20000007, /* Scatter Gather overrun  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS      = 0x20000008, /* Receiver detected context mismatch via invalid header */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE       = 0x2000000A, /* Link failure occurred  */
+    MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT         = 0x2000000B, /* Transmitter timeout error */
+
+    MPI_IOCLOGINFO_FC_TARGET_BASE                   = 0x21000000,
+    MPI_IOCLOGINFO_FC_TARGET_NO_PDISC               = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
+    MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN               = 0x21000002, /* not sent because we are not logged in to the remote node */
+    MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP     = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP     = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA      = 0x21000005, /* Data In, Auto Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP     = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP     = 0x21000007, /* Auto-response after a write not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP     = 0x21000008, /* Data In, No Response, not completed due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA      = 0x21000009, /* Data In, No Response, missing data frames */
+    MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP     = 0x2100000a, /* Manual Response not sent due to a LIP */
+    MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3             = 0x2100000b, /* not sent because remote node does not support Class 3 */
+    MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID        = 0x2100000c, /* not sent because login to remote node not validated */
+    MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND          = 0x2100000e, /* cleared from the outbound queue after a logout */
+    MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN    = 0x2100000f, /* cleared waiting for data after a logout */
+
+    MPI_IOCLOGINFO_FC_LAN_BASE                      = 0x22000000,
+    MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING         = 0x22000001, /* Transaction Context Sgl Missing */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE         = 0x22000002, /* Transaction Context found before an EOB */
+    MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET        = 0x22000003, /* Transaction Context value has reserved bits set */
+    MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG            = 0x22000004, /* Invalid SGL Flags */
+
+    MPI_IOCLOGINFO_FC_MSG_BASE                      = 0x23000000,
+
+    MPI_IOCLOGINFO_FC_LINK_BASE                     = 0x24000000,
+    MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT        = 0x24000001, /* Loop initialization timed out */
+    MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED      = 0x24000002, /* Another system controller already initialized the loop */
+    MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED     = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
+    MPI_IOCLOGINFO_FC_LINK_CRC_ERROR                = 0x24000004, /* CRC check detected error on received frame */
+
+    MPI_IOCLOGINFO_FC_CTX_BASE                      = 0x25000000,
+
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET     = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */
+    MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET      = 0x26ffffff,
+
+    MPI_IOCLOGINFO_FC_STATE_CHANGE                  = 0x27000000  /* The lower 24 bits give additional information concerning state change */
+
+} MpiIocLogInfoFc_t;
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
new file mode 100644 (file)
index 0000000..9259d1a
--- /dev/null
@@ -0,0 +1,162 @@
+
+/***************************************************************************
+ *                                                                         *
+ *  Copyright 2003 LSI Logic Corporation.  All rights reserved.            *
+ *                                                                         *
+ *  This file is confidential and a trade secret of LSI Logic.  The        *
+ *  receipt of or possession of this file does not convey any rights to    *
+ *  reproduce or disclose its contents or to manufacture, use, or sell     *
+ *  anything it may describe, in whole, or in part, without the specific   *
+ *  written consent of LSI Logic Corporation.                              *
+ *                                                                         *
+ ***************************************************************************
+ *
+ *           Name:  iopiIocLogInfo.h
+ *          Title:  SAS Firmware IOP Interface IOC Log Info Definitions
+ *     Programmer:  Guy Kendall
+ *  Creation Date:  September 24, 2003
+ *
+ *  Version History
+ *  ---------------
+ *
+ *  Last Updated
+ *  -------------
+ *  Version         %version: 22 %
+ *  Date Updated    %date_modified: %
+ *  Programmer      %created_by: nperucca %
+ *
+ *  Date      Who   Description
+ *  --------  ---   -------------------------------------------------------
+ *  09/24/03  GWK   Initial version
+ *
+ *
+ * Description
+ * ------------
+ * This include file contains SAS firmware interface IOC Log Info codes
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef IOPI_IOCLOGINFO_H_INCLUDED
+#define IOPI_IOCLOGINFO_H_INCLUDED
+
+
+/****************************************************************************/
+/*  IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF                            */
+/*  Format:                                                                 */
+/*      Bits 31-28: MPI_IOCLOGINFO_TYPE_SAS (3)                             */
+/*      Bits 27-24: IOC_LOGINFO_ORIGINATOR: 0=IOP, 1=PL, 2=IR               */
+/*      Bits 23-16: LOGINFO_CODE                                            */
+/*      Bits 15-0:  LOGINFO_CODE Specific                                   */
+/****************************************************************************/
+
+/****************************************************************************/
+/* IOC_LOGINFO_ORIGINATOR defines                                           */
+/****************************************************************************/
+#define IOC_LOGINFO_ORIGINATOR_IOP                      (0x00000000)
+#define IOC_LOGINFO_ORIGINATOR_PL                       (0x01000000)
+#define IOC_LOGINFO_ORIGINATOR_IR                       (0x02000000)
+
+/****************************************************************************/
+/* LOGINFO_CODE defines                                                     */
+/****************************************************************************/
+#define IOC_LOGINFO_CODE_MASK                           (0x00FF0000)
+#define IOC_LOGINFO_CODE_SHIFT                          (16)
+
+/****************************************************************************/
+/* IOP LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IOP          */
+/****************************************************************************/
+#define IOP_LOGINFO_CODE_INVALID_SAS_ADDRESS            (0x00010000)
+#define IOP_LOGINFO_CODE_UNUSED2                        (0x00020000)
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE            (0x00030000)
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_RT         (0x00030100) /* Route Table Entry not found */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PN         (0x00030200) /* Invalid Page Number */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM       (0x00030300) /* Invalid FORM */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT         (0x00030400) /* Invalid Page Type */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM        (0x00030500) /* Device Not Mapped */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST    (0x00030600) /* Persistent Page not found */
+#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT    (0x00030700) /* Default Page not found */
+#define IOP_LOGINFO_CODE_TASK_TERMINATED                (0x00050000)
+
+
+/****************************************************************************/
+/* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL            */
+/****************************************************************************/
+#define PL_LOGINFO_CODE_OPEN_FAILURE                        (0x00010000)
+#define PL_LOGINFO_CODE_INVALID_SGL                         (0x00020000)
+#define PL_LOGINFO_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH       (0x00030000)
+#define PL_LOGINFO_CODE_FRAME_XFER_ERROR                    (0x00040000)
+#define PL_LOGINFO_CODE_TX_FM_CONNECTED_LOW                 (0x00050000)
+#define PL_LOGINFO_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET         (0x00060000)
+#define PL_LOGINFO_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR      (0x00070000)
+#define PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR     (0x00080000)
+#define PL_LOGINFO_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS     (0x00090000)
+#define PL_LOGINFO_CODE_RX_FM_INVALID_MESSAGE               (0x000A0000)
+#define PL_LOGINFO_CODE_RX_CTX_MESSAGE_VALID_ERROR          (0x000B0000)
+#define PL_LOGINFO_CODE_RX_FM_CURRENT_FRAME_ERROR           (0x000C0000)
+#define PL_LOGINFO_CODE_SATA_LINK_DOWN                      (0x000D0000)
+#define PL_LOGINFO_CODE_DISCOVERY_SATA_INIT_W_IOS           (0x000E0000)
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE                 (0x000F0000)
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PT              (0x000F0100) /* Invalid Page Type */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NUM_PHYS        (0x000F0200) /* Invalid Number of Phys */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NOT_IMP         (0x000F0300) /* Case Not Handled */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_DEV          (0x000F0400) /* No Device Found */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_FORM            (0x000F0500) /* Invalid FORM */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_PHY             (0x000F0600) /* Invalid Phy */
+#define PL_LOGINFO_CODE_CONFIG_INVALID_PAGE_NO_OWNER        (0x000F0700) /* No Owner Found */
+#define PL_LOGINFO_CODE_DSCVRY_SATA_INIT_TIMEOUT            (0x00100000)
+#define PL_LOGINFO_CODE_RESET                               (0x00110000)
+#define PL_LOGINFO_CODE_ABORT                               (0x00120000)
+#define PL_LOGINFO_CODE_IO_NOT_YET_EXECUTED                 (0x00130000)
+#define PL_LOGINFO_CODE_IO_EXECUTED                         (0x00140000)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE                    (0x00000100)
+#define PL_LOGINFO_SUB_CODE_INVALID_SGL                     (0x00000200)
+#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH   (0x00000300)
+#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR                (0x00000400)
+#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW             (0x00000500)
+#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET     (0x00000600)
+#define PL_LOGINFO_SUB_CODE_SATA_READ_LOG_RECEIVE_DATA_ERR  (0x00000700)
+#define PL_LOGINFO_SUB_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR (0x00000800)
+#define PL_LOGINFO_SUB_CODE_SATA_ERR_IN_RCV_SET_DEV_BIT_FIS (0x00000900)
+#define PL_LOGINFO_SUB_CODE_RX_FM_INVALID_MESSAGE           (0x00000A00)
+#define PL_LOGINFO_SUB_CODE_RX_CTX_MESSAGE_VALID_ERROR      (0x00000B00)
+#define PL_LOGINFO_SUB_CODE_RX_FM_CURRENT_FRAME_ERROR       (0x00000C00)
+#define PL_LOGINFO_SUB_CODE_SATA_LINK_DOWN                  (0x00000D00)
+#define PL_LOGINFO_SUB_CODE_DISCOVERY_SATA_INIT_W_IOS       (0x00000E00)
+#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT        (0x00001000)
+
+
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE         (0x00200000) /* Can't get SMP Frame */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR            (0x00200001) /* Error occured on SMP Read */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR           (0x00200002) /* Error occured on SMP Write */
+#define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL     (0x00200004) /* Encl Mgmt services not available for this WWID */
+#define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED   (0x00200005) /* Address Mode not suppored */
+#define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM              (0x00200006) /* Invalid Slot Number in SEP Msg */
+#define PL_LOGINFO_CODE_ENCL_MGMT_SGPIO_NOT_PRESENT         (0x00200007) /* SGPIO not present/enabled */
+
+#define PL_LOGINFO_DA_SEP_NOT_PRESENT                       (0x00200100) /* SEP not present when msg received */
+#define PL_LOGINFO_DA_SEP_SINGLE_THREAD_ERROR               (0x00200101) /* Can only accept 1 msg at a time */
+#define PL_LOGINFO_DA_SEP_ISTWI_INTR_IN_IDLE_STATE          (0x00200102) /* ISTWI interrupt recvd. while IDLE */
+#define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE          (0x00200103) /* SEP NACK'd, it is busy */
+#define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM             (0x00200104) /* SEP stopped or sent bad chksum in Hdr */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1         (0x00200105) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2         (0x00200106) /* SEP returned unknown scsi status */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP           (0x00200107) /* SEP returned bad chksum after STOP */
+#define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP_GETDATA   (0x00200108) /* SEP returned bad chksum after STOP while gettin data*/
+
+
+/****************************************************************************/
+/* IR LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IR            */
+/****************************************************************************/
+#define IR_LOGINFO_CODE_UNUSED1                         (0x00010000)
+#define IR_LOGINFO_CODE_UNUSED2                         (0x00020000)
+
+/****************************************************************************/
+/* Defines for convienence                                                  */
+/****************************************************************************/
+#define IOC_LOGINFO_PREFIX_IOP                          ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IOP)
+#define IOC_LOGINFO_PREFIX_PL                           ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_PL)
+#define IOC_LOGINFO_PREFIX_IR                           ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IR)
+
+#endif /* end of file */
+
index 230fa69b5353426566599270d0ce117d8a7c4279..70514867bddf3befa735d75404b88c5d8bd84ea1 100644 (file)
@@ -6,7 +6,7 @@
  *          Title:  MPI Serial Attached SCSI structures and definitions
  *  Creation Date:  August 19, 2004
  *
- *    mpi_sas.h Version:  01.05.01
+ *    mpi_sas.h Version:  01.05.02
  *
  *  Version History
  *  ---------------
@@ -14,6 +14,9 @@
  *  Date      Version   Description
  *  --------  --------  ------------------------------------------------------
  *  08-19-04  01.05.01  Original release.
+ *  08-30-05  01.05.02  Added DeviceInfo bit for SEP.
+ *                      Added PrimFlags and Primitive field to SAS IO Unit
+ *                      Control request, and added a new operation code.
  *  --------------------------------------------------------------------------
  */
 
@@ -51,6 +54,7 @@
  * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
  * data and SAS IO Unit Configuration pages.
  */
+#define MPI_SAS_DEVICE_INFO_SEP                 (0x00004000)
 #define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE        (0x00002000)
 #define MPI_SAS_DEVICE_INFO_LSI_DEVICE          (0x00001000)
 #define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH       (0x00000800)
@@ -212,20 +216,26 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
     U8                      TargetID;           /* 0Ch */
     U8                      Bus;                /* 0Dh */
     U8                      PhyNum;             /* 0Eh */
-    U8                      Reserved4;          /* 0Fh */
-    U32                     Reserved5;          /* 10h */
+    U8                      PrimFlags;          /* 0Fh */
+    U32                     Primitive;          /* 10h */
     U64                     SASAddress;         /* 14h */
-    U32                     Reserved6;          /* 1Ch */
+    U32                     Reserved4;          /* 1Ch */
 } MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST,
   SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t;
 
 /* values for the Operation field */
-#define MPI_SAS_OP_CLEAR_NOT_PRESENT             (0x01)
-#define MPI_SAS_OP_CLEAR_ALL_PERSISTENT          (0x02)
-#define MPI_SAS_OP_PHY_LINK_RESET                (0x06)
-#define MPI_SAS_OP_PHY_HARD_RESET                (0x07)
-#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG           (0x08)
-#define MPI_SAS_OP_MAP_CURRENT                   (0x09)
+#define MPI_SAS_OP_CLEAR_NOT_PRESENT            (0x01)
+#define MPI_SAS_OP_CLEAR_ALL_PERSISTENT         (0x02)
+#define MPI_SAS_OP_PHY_LINK_RESET               (0x06)
+#define MPI_SAS_OP_PHY_HARD_RESET               (0x07)
+#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG          (0x08)
+#define MPI_SAS_OP_MAP_CURRENT                  (0x09)
+#define MPI_SAS_OP_SEND_PRIMITIVE               (0x0A)
+
+/* values for the PrimFlags field */
+#define MPI_SAS_PRIMFLAGS_SINGLE                (0x08)
+#define MPI_SAS_PRIMFLAGS_TRIPLE                (0x02)
+#define MPI_SAS_PRIMFLAGS_REDUNDANT             (0x01)
 
 
 /* SAS IO Unit Control Reply */
index 537836068c493736d1efc7a3139974d16faeacc1..d890b2b8a93e94973f345068f95b75e9121b679d 100644 (file)
@@ -148,7 +148,6 @@ static int  WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
 static int     GetLanConfigPages(MPT_ADAPTER *ioc);
-static int     GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 static int     GetIoUnitPage2(MPT_ADAPTER *ioc);
 int            mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
 static int     mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
@@ -1232,12 +1231,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                dprintk((KERN_INFO MYNAM
                        ": Not using 64 bit consistent mask\n"));
 
-       ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+       ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
        if (ioc == NULL) {
                printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
                return -ENOMEM;
        }
-       memset(ioc, 0, sizeof(MPT_ADAPTER));
        ioc->alloc_total = sizeof(MPT_ADAPTER);
        ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;           /* avoid div by zero! */
        ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
@@ -1245,6 +1243,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
        ioc->pcidev = pdev;
        ioc->diagPending = 0;
        spin_lock_init(&ioc->diagLock);
+       spin_lock_init(&ioc->fc_rescan_work_lock);
+       spin_lock_init(&ioc->fc_rport_lock);
        spin_lock_init(&ioc->initializing_hba_lock);
 
        /* Initialize the event logging.
@@ -1268,6 +1268,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
         */
        INIT_LIST_HEAD(&ioc->configQ);
 
+       /* Initialize the fc rport list head.
+        */
+       INIT_LIST_HEAD(&ioc->fc_rports);
+
        /* Find lookup slot. */
        INIT_LIST_HEAD(&ioc->list);
        ioc->id = mpt_ids++;
@@ -1374,6 +1378,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
                ioc->bus_type = FC;
                ioc->errata_flag_1064 = 1;
        }
+       else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
+               ioc->prod_name = "LSIFC949E";
+               ioc->bus_type = FC;
+       }
        else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
                ioc->prod_name = "LSI53C1030";
                ioc->bus_type = SPI;
@@ -1622,7 +1630,7 @@ mpt_resume(struct pci_dev *pdev)
        pci_enable_device(pdev);
 
        /* enable interrupts */
-       CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+       CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
        ioc->active = 1;
 
        /* F/W not running */
@@ -1715,7 +1723,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                                /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
                                dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
                                                ioc->alt_ioc->name));
-                               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+                               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                                ioc->alt_ioc->active = 1;
                        }
 
@@ -1831,7 +1839,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
 
        if (ret == 0) {
                /* Enable! (reply interrupt) */
-               CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM));
+               CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->active = 1;
        }
 
@@ -1839,7 +1847,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                /* (re)Enable alt-IOC! (reply interrupt) */
                dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
                                ioc->alt_ioc->name));
-               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM));
+               CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
                ioc->alt_ioc->active = 1;
        }
 
@@ -1880,7 +1888,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
                         *  (FCPortPage0_t stuff)
                         */
                        for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
-                               (void) GetFcPortPage0(ioc, ii);
+                               (void) mptbase_GetFcPortPage0(ioc, ii);
                        }
 
                        if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
@@ -4199,7 +4207,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *     GetFcPortPage0 - Fetch FCPort config Page0.
+ *     mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
  *     @ioc: Pointer to MPT_ADAPTER structure
  *     @portnum: IOC Port number
  *
@@ -4209,8 +4217,8 @@ GetLanConfigPages(MPT_ADAPTER *ioc)
  *             -EAGAIN if no msg frames currently available
  *             -EFAULT for non-successful reply or no reply (timeout)
  */
-static int
-GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+int
+mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
 {
        ConfigPageHeader_t       hdr;
        CONFIGPARMS              cfg;
@@ -4220,6 +4228,8 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
        int                      data_sz;
        int                      copy_sz;
        int                      rc;
+       int                      count = 400;
+
 
        /* Get FCPort Page 0 header */
        hdr.PageVersion = 0;
@@ -4243,6 +4253,8 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
        rc = -ENOMEM;
        ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
        if (ppage0_alloc) {
+
+ try_again:
                memset((u8 *)ppage0_alloc, 0, data_sz);
                cfg.physAddr = page0_dma;
                cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
@@ -4274,6 +4286,19 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
                        pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
                        pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
 
+                       /*
+                        * if still doing discovery,
+                        * hang loose a while until finished
+                        */
+                       if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
+                               if (count-- > 0) {
+                                       msleep_interruptible(100);
+                                       goto try_again;
+                               }
+                               printk(MYIOC_s_INFO_FMT "Firmware discovery not"
+                                                       " complete.\n",
+                                               ioc->name);
+                       }
                }
 
                pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -6358,6 +6383,7 @@ EXPORT_SYMBOL(mpt_alloc_fw_memory);
 EXPORT_SYMBOL(mpt_free_fw_memory);
 EXPORT_SYMBOL(mptbase_sas_persist_operation);
 EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
index 6c48d1f54ac92552b4fdf42f4ebbf66c74d5eda9..47053ac65068566fa6675fa2a5ed08eb8199684e 100644 (file)
@@ -76,8 +76,8 @@
 #define COPYRIGHT      "Copyright (c) 1999-2005 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON       "3.03.05"
-#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.03.05"
+#define MPT_LINUX_VERSION_COMMON       "3.03.06"
+#define MPT_LINUX_PACKAGE_NAME         "@(#)mptlinux-3.03.06"
 #define WHAT_MAGIC_STRING              "@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -413,7 +413,7 @@ typedef struct _MPT_IOCTL {
        u8                       status;        /* current command status */
        u8                       reset;         /* 1 if bus reset allowed */
        u8                       target;        /* target for reset */
-       struct semaphore         sem_ioc;
+       struct mutex             ioctl_mutex;
 } MPT_IOCTL;
 
 #define MPT_SAS_MGMT_STATUS_RF_VALID   0x02    /* The Reply Frame is VALID */
@@ -421,7 +421,7 @@ typedef struct _MPT_IOCTL {
 #define MPT_SAS_MGMT_STATUS_TM_FAILED  0x40    /* User TM request failed */
 
 typedef struct _MPT_SAS_MGMT {
-       struct semaphore         mutex;
+       struct mutex             mutex;
        struct completion        done;
        u8                       reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */
        u8                       status;        /* current command status */
@@ -499,6 +499,22 @@ typedef    struct _RaidCfgData {
        int              isRaid;                /* bit field, 1 if RAID */
 }RaidCfgData;
 
+#define MPT_RPORT_INFO_FLAGS_REGISTERED        0x01    /* rport registered */
+#define MPT_RPORT_INFO_FLAGS_MISSING   0x02    /* missing from DevPage0 scan */
+#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04  /* target mapped in vdev */
+
+/*
+ * data allocated for each fc rport device
+ */
+struct mptfc_rport_info
+{
+       struct list_head list;
+       struct fc_rport *rport;
+       VirtDevice      *vdev;
+       FCDevicePage0_t pg0;
+       u8              flags;
+};
+
 /*
  *  Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
  */
@@ -612,7 +628,16 @@ typedef struct _MPT_ADAPTER
        struct list_head         list;
        struct net_device       *netdev;
        struct list_head         sas_topology;
+       struct mutex             sas_topology_mutex;
        MPT_SAS_MGMT             sas_mgmt;
+       int                      num_ports;
+
+       struct list_head         fc_rports;
+       spinlock_t               fc_rport_lock; /* list and ri flags */
+       spinlock_t               fc_rescan_work_lock;
+       int                      fc_rescan_work_count;
+       struct work_struct       fc_rescan_work;
+
 } MPT_ADAPTER;
 
 /*
@@ -999,6 +1024,7 @@ extern void         mpt_free_fw_memory(MPT_ADAPTER *ioc);
 extern int      mpt_findImVolumes(MPT_ADAPTER *ioc);
 extern int      mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
 extern int      mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+extern int      mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
 extern int      mpt_alt_ioc_wait(MPT_ADAPTER *ioc);
 
 /*
index 7c340240a50e94f1258fd3c2b5d19c3f079740d0..bdf709987982b37509646e553f2482dd2d3d60c7 100644 (file)
@@ -177,10 +177,10 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
        dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
 
        if (nonblock) {
-               if (down_trylock(&ioc->ioctl->sem_ioc))
+               if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
                        rc = -EAGAIN;
        } else {
-               if (down_interruptible(&ioc->ioctl->sem_ioc))
+               if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
                        rc = -ERESTARTSYS;
        }
        dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
@@ -557,7 +557,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        else
                ret = -EINVAL;
 
-       up(&iocp->ioctl->sem_ioc);
+       mutex_unlock(&iocp->ioctl->ioctl_mutex);
 
        return ret;
 }
@@ -2619,7 +2619,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
 
        ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen);
 
-       up(&iocp->ioctl->sem_ioc);
+       mutex_unlock(&iocp->ioctl->ioctl_mutex);
 
        return ret;
 }
@@ -2673,7 +2673,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
         */
        ret = mptctl_do_mpt_command (karg, &uarg->MF);
 
-       up(&iocp->ioctl->sem_ioc);
+       mutex_unlock(&iocp->ioctl->ioctl_mutex);
 
        return ret;
 }
@@ -2743,7 +2743,7 @@ mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        memset(mem, 0, sz);
        ioc->ioctl = (MPT_IOCTL *) mem;
        ioc->ioctl->ioc = ioc;
-       sema_init(&ioc->ioctl->sem_ioc, 1);
+       mutex_init(&ioc->ioctl->ioctl_mutex);
        return 0;
 
 out_fail:
index ba61e18288585679d4915c9ec22abd82804496b7..b102c7666d0efcaf44f8a6e534ff340352b23489 100644 (file)
 #include <linux/reboot.h>      /* notifier code */
 #include <linux/sched.h>
 #include <linux/workqueue.h>
+#include <linux/sort.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
 
 #include "mptbase.h"
 #include "mptscsih.h"
@@ -79,19 +81,34 @@ static int mpt_pq_filter = 0;
 module_param(mpt_pq_filter, int, 0);
 MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1  (default=0)");
 
+#define MPTFC_DEV_LOSS_TMO (60)
+static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;    /* reasonable default */
+module_param(mptfc_dev_loss_tmo, int, 0);
+MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the "
+                                    " transport to wait for an rport to "
+                                    " return following a device loss event."
+                                    "  Default=60.");
+
 static int     mptfcDoneCtx = -1;
 static int     mptfcTaskCtx = -1;
 static int     mptfcInternalCtx = -1; /* Used only for internal commands */
 
+int mptfc_slave_alloc(struct scsi_device *device);
+static int mptfc_qcmd(struct scsi_cmnd *SCpnt,
+    void (*done)(struct scsi_cmnd *));
+
+static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
+static void __devexit mptfc_remove(struct pci_dev *pdev);
+
 static struct scsi_host_template mptfc_driver_template = {
        .module                         = THIS_MODULE,
        .proc_name                      = "mptfc",
        .proc_info                      = mptscsih_proc_info,
        .name                           = "MPT FC Host",
        .info                           = mptscsih_info,
-       .queuecommand                   = mptscsih_qcmd,
+       .queuecommand                   = mptfc_qcmd,
        .target_alloc                   = mptscsih_target_alloc,
-       .slave_alloc                    = mptscsih_slave_alloc,
+       .slave_alloc                    = mptfc_slave_alloc,
        .slave_configure                = mptscsih_slave_configure,
        .target_destroy                 = mptscsih_target_destroy,
        .slave_destroy                  = mptscsih_slave_destroy,
@@ -128,19 +145,478 @@ static struct pci_device_id mptfc_pci_table[] = {
                PCI_ANY_ID, PCI_ANY_ID },
        { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
                PCI_ANY_ID, PCI_ANY_ID },
+       { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES,
+               PCI_ANY_ID, PCI_ANY_ID },
        {0}     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct scsi_transport_template *mptfc_transport_template = NULL;
+
+struct fc_function_template mptfc_transport_functions = {
+       .dd_fcrport_size = 8,
+       .show_host_node_name = 1,
+       .show_host_port_name = 1,
+       .show_host_supported_classes = 1,
+       .show_host_port_id = 1,
+       .show_rport_supported_classes = 1,
+       .show_starget_node_name = 1,
+       .show_starget_port_name = 1,
+       .show_starget_port_id = 1,
+       .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
+       .show_rport_dev_loss_tmo = 1,
+
+};
+
+/* FIXME! values controlling firmware RESCAN event
+ * need to be set low to allow dev_loss_tmo to
+ * work as expected.  Currently, firmware doesn't
+ * notify driver of RESCAN event until some number
+ * of seconds elapse.  This value can be set via
+ * lsiutil.
+ */
+static void
+mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+       if (timeout > 0)
+               rport->dev_loss_tmo = timeout;
+       else
+               rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+}
+
+static int
+mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
+{
+       FCDevicePage0_t **aa = (FCDevicePage0_t **)a;
+       FCDevicePage0_t **bb = (FCDevicePage0_t **)b;
+
+       if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
+               if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
+                       return 0;
+               if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
+                       return -1;
+               return 1;
+       }
+       if ((*aa)->CurrentBus < (*bb)->CurrentBus)
+               return -1;
+       return 1;
+}
+
+static int
+mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
+       void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
+{
+       ConfigPageHeader_t       hdr;
+       CONFIGPARMS              cfg;
+       FCDevicePage0_t         *ppage0_alloc, *fc;
+       dma_addr_t               page0_dma;
+       int                      data_sz;
+       int                      ii;
+
+       FCDevicePage0_t         *p0_array=NULL, *p_p0;
+       FCDevicePage0_t         **pp0_array=NULL, **p_pp0;
+
+       int                      rc = -ENOMEM;
+       U32                      port_id = 0xffffff;
+       int                      num_targ = 0;
+       int                      max_bus = ioc->facts.MaxBuses;
+       int                      max_targ = ioc->facts.MaxDevices;
+
+       if (max_bus == 0 || max_targ == 0)
+               goto out;
+
+       data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
+       p_p0 = p0_array =  kzalloc(data_sz, GFP_KERNEL);
+       if (!p0_array)
+               goto out;
+
+       data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
+       p_pp0 = pp0_array = kzalloc(data_sz, GFP_KERNEL);
+       if (!pp0_array)
+               goto out;
+
+       do {
+               /* Get FC Device Page 0 header */
+               hdr.PageVersion = 0;
+               hdr.PageLength = 0;
+               hdr.PageNumber = 0;
+               hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
+               cfg.cfghdr.hdr = &hdr;
+               cfg.physAddr = -1;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+               cfg.dir = 0;
+               cfg.pageAddr = port_id;
+               cfg.timeout = 0;
+
+               if ((rc = mpt_config(ioc, &cfg)) != 0)
+                       break;
+
+               if (hdr.PageLength <= 0)
+                       break;
+
+               data_sz = hdr.PageLength * 4;
+               ppage0_alloc = pci_alloc_consistent(ioc->pcidev, data_sz,
+                                                       &page0_dma);
+               rc = -ENOMEM;
+               if (!ppage0_alloc)
+                       break;
+
+               cfg.physAddr = page0_dma;
+               cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+               if ((rc = mpt_config(ioc, &cfg)) == 0) {
+                       ppage0_alloc->PortIdentifier =
+                               le32_to_cpu(ppage0_alloc->PortIdentifier);
+
+                       ppage0_alloc->WWNN.Low =
+                               le32_to_cpu(ppage0_alloc->WWNN.Low);
+
+                       ppage0_alloc->WWNN.High =
+                               le32_to_cpu(ppage0_alloc->WWNN.High);
+
+                       ppage0_alloc->WWPN.Low =
+                               le32_to_cpu(ppage0_alloc->WWPN.Low);
+
+                       ppage0_alloc->WWPN.High =
+                               le32_to_cpu(ppage0_alloc->WWPN.High);
+
+                       ppage0_alloc->BBCredit =
+                               le16_to_cpu(ppage0_alloc->BBCredit);
+
+                       ppage0_alloc->MaxRxFrameSize =
+                               le16_to_cpu(ppage0_alloc->MaxRxFrameSize);
+
+                       port_id = ppage0_alloc->PortIdentifier;
+                       num_targ++;
+                       *p_p0 = *ppage0_alloc;  /* save data */
+                       *p_pp0++ = p_p0++;      /* save addr */
+               }
+               pci_free_consistent(ioc->pcidev, data_sz,
+                                       (u8 *) ppage0_alloc, page0_dma);
+               if (rc != 0)
+                       break;
+
+       } while (port_id <= 0xff0000);
+
+       if (num_targ) {
+               /* sort array */
+               if (num_targ > 1)
+                       sort (pp0_array, num_targ, sizeof(FCDevicePage0_t *),
+                               mptfc_FcDevPage0_cmp_func, NULL);
+               /* call caller's func for each targ */
+               for (ii = 0; ii < num_targ;  ii++) {
+                       fc = *(pp0_array+ii);
+                       func(ioc, ioc_port, fc);
+               }
+       }
+
+ out:
+       if (pp0_array)
+               kfree(pp0_array);
+       if (p0_array)
+               kfree(p0_array);
+       return rc;
+}
+
+static int
+mptfc_generate_rport_ids(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
+{
+       /* not currently usable */
+       if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
+                         MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
+               return -1;
+
+       if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
+               return -1;
+
+       if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
+               return -1;
+
+       /*
+        * board data structure already normalized to platform endianness
+        * shifted to avoid unaligned access on 64 bit architecture
+        */
+       rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
+       rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
+       rid->port_id =   pg0->PortIdentifier;
+       rid->roles = FC_RPORT_ROLE_UNKNOWN;
+       rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
+       if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+               rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
+       return 0;
+}
+
+static void
+mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
+{
+       struct fc_rport_identifiers rport_ids;
+       struct fc_rport         *rport;
+       struct mptfc_rport_info *ri;
+       int                     match = 0;
+       u64                     port_name;
+       unsigned long           flags;
+
+       if (mptfc_generate_rport_ids(pg0, &rport_ids) < 0)
+               return;
+
+       /* scan list looking for a match */
+       spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+       list_for_each_entry(ri, &ioc->fc_rports, list) {
+               port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+               if (port_name == rport_ids.port_name) { /* match */
+                       list_move_tail(&ri->list, &ioc->fc_rports);
+                       match = 1;
+                       break;
+               }
+       }
+       if (!match) {   /* allocate one */
+               spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
+               ri = kzalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
+               if (!ri)
+                       return;
+               spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+               list_add_tail(&ri->list, &ioc->fc_rports);
+       }
+
+       ri->pg0 = *pg0; /* add/update pg0 data */
+       ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
+
+       if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
+               ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
+               spin_unlock_irqrestore(&ioc->fc_rport_lock, flags);
+               rport = fc_remote_port_add(ioc->sh,channel, &rport_ids);
+               spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+               if (rport) {
+                       if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
+                               ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+                               ri->vdev = NULL;
+                               ri->rport = rport;
+                               *((struct mptfc_rport_info **)rport->dd_data) = ri;
+                       }
+                       rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+                       /*
+                        * if already mapped, remap here.  If not mapped,
+                        * slave_alloc will allocate vdev and map
+                        */
+                       if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
+                               ri->vdev->target_id = ri->pg0.CurrentTargetID;
+                               ri->vdev->bus_id = ri->pg0.CurrentBus;
+                               ri->vdev->vtarget->target_id = ri->vdev->target_id;
+                               ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
+                       }
+                       #ifdef MPT_DEBUG
+                       printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
+                               "rport tid %d, tmo %d\n",
+                                       ioc->sh->host_no,
+                                       pg0->PortIdentifier,
+                                       pg0->WWNN,
+                                       pg0->WWPN,
+                                       pg0->CurrentTargetID,
+                                       ri->rport->scsi_target_id,
+                                       ri->rport->dev_loss_tmo);
+                       #endif
+               } else {
+                       list_del(&ri->list);
+                       kfree(ri);
+                       ri = NULL;
+               }
+       }
+       spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+}
+
 /*
- *     mptfc_probe - Installs scsi devices per bus.
- *     @pdev: Pointer to pci_dev structure
- *
- *     Returns 0 for success, non-zero for failure.
- *
+ *     OS entry point to allow host driver to alloc memory
+ *     for each scsi device. Called once per device the bus scan.
+ *     Return non-zero if allocation fails.
+ *     Init memory once per LUN.
  */
+int
+mptfc_slave_alloc(struct scsi_device *sdev)
+{
+       MPT_SCSI_HOST           *hd;
+       VirtTarget              *vtarget;
+       VirtDevice              *vdev;
+       struct scsi_target      *starget;
+       struct fc_rport         *rport;
+       struct mptfc_rport_info *ri;
+       unsigned long           flags;
+
+
+       rport = starget_to_rport(scsi_target(sdev));
+
+       if (!rport || fc_remote_port_chkready(rport))
+               return -ENXIO;
+
+       hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+
+       vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+       if (!vdev) {
+               printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+                               hd->ioc->name, sizeof(VirtDevice));
+               return -ENOMEM;
+       }
+       memset(vdev, 0, sizeof(VirtDevice));
+
+       spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
+
+       if (!(ri = *((struct mptfc_rport_info **)rport->dd_data))) {
+               spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+               kfree(vdev);
+               return -ENODEV;
+       }
+
+       sdev->hostdata = vdev;
+       starget = scsi_target(sdev);
+       vtarget = starget->hostdata;
+       if (vtarget->num_luns == 0) {
+               vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
+                                 MPT_TARGET_FLAGS_VALID_INQUIRY;
+               hd->Targets[sdev->id] = vtarget;
+       }
+
+       vtarget->target_id = vdev->target_id;
+       vtarget->bus_id = vdev->bus_id;
+
+       vdev->vtarget = vtarget;
+       vdev->ioc_id = hd->ioc->id;
+       vdev->lun = sdev->lun;
+       vdev->target_id = ri->pg0.CurrentTargetID;
+       vdev->bus_id = ri->pg0.CurrentBus;
+
+       ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+       ri->vdev = vdev;
+
+       spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+
+       vtarget->num_luns++;
+
+#ifdef MPT_DEBUG
+       printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
+               "CurrentTargetID %d, %x %llx %llx\n",
+                       sdev->host->host_no,
+                       vtarget->num_luns,
+                       sdev->id, ri->pg0.CurrentTargetID,
+                       ri->pg0.PortIdentifier, ri->pg0.WWPN, ri->pg0.WWNN);
+#endif
+
+       return 0;
+}
+
+static int
+mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+       struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
+       int             err;
+
+       err = fc_remote_port_chkready(rport);
+       if (unlikely(err)) {
+               SCpnt->result = err;
+               done(SCpnt);
+               return 0;
+       }
+       return mptscsih_qcmd(SCpnt,done);
+}
+
+static void
+mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
+{
+       unsigned class = 0, cos = 0;
+
+       /* don't know what to do as only one scsi (fc) host was allocated */
+       if (portnum != 0)
+               return;
+
+       class = ioc->fc_port_page0[portnum].SupportedServiceClass;
+       if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
+               cos |= FC_COS_CLASS1;
+       if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
+               cos |= FC_COS_CLASS2;
+       if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
+               cos |= FC_COS_CLASS3;
+
+       fc_host_node_name(ioc->sh) =
+               (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
+                   | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
+
+       fc_host_port_name(ioc->sh) =
+               (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
+                   | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
+
+       fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
+
+       fc_host_supported_classes(ioc->sh) = cos;
+
+       fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
+}
+
+static void
+mptfc_rescan_devices(void *arg)
+{
+       MPT_ADAPTER             *ioc = (MPT_ADAPTER *)arg;
+       int                     ii;
+       int                     work_to_do;
+       unsigned long           flags;
+       struct mptfc_rport_info *ri;
+
+       do {
+               /* start by tagging all ports as missing */
+               spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+               list_for_each_entry(ri, &ioc->fc_rports, list) {
+                       if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+                               ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
+                       }
+               }
+               spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+               /*
+                * now rescan devices known to adapter,
+                * will reregister existing rports
+                */
+               for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+                       (void) mptbase_GetFcPortPage0(ioc, ii);
+                       mptfc_init_host_attr(ioc,ii);   /* refresh */
+                       mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+               }
+
+               /* delete devices still missing */
+               spin_lock_irqsave(&ioc->fc_rport_lock, flags);
+               list_for_each_entry(ri, &ioc->fc_rports, list) {
+                       /* if newly missing, delete it */
+                       if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
+                                         MPT_RPORT_INFO_FLAGS_MISSING))
+                         == (MPT_RPORT_INFO_FLAGS_REGISTERED |
+                             MPT_RPORT_INFO_FLAGS_MISSING)) {
+
+                               ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
+                                              MPT_RPORT_INFO_FLAGS_MISSING);
+                               fc_remote_port_delete(ri->rport);
+                               /*
+                                * remote port not really deleted 'cause
+                                * binding is by WWPN and driver only
+                                * registers FCP_TARGETs
+                                */
+                               #ifdef MPT_DEBUG
+                               printk ("mptfc_rescan.%d: %llx deleted\n",
+                                       ioc->sh->host_no, ri->pg0.WWPN);
+                               #endif
+                       }
+               }
+               spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+               /*
+                * allow multiple passes as target state
+                * might have changed during scan
+                */
+               spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+               if (ioc->fc_rescan_work_count > 2)      /* only need one more */
+                       ioc->fc_rescan_work_count = 2;
+               work_to_do = --ioc->fc_rescan_work_count;
+               spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+       } while (work_to_do);
+}
+
 static int
 mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -148,17 +624,16 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        MPT_SCSI_HOST           *hd;
        MPT_ADAPTER             *ioc;
        unsigned long            flags;
-       int                      sz, ii;
+       int                      ii;
        int                      numSGE = 0;
        int                      scale;
        int                      ioc_cap;
-       u8                      *mem;
        int                     error=0;
        int                     r;
-               
+
        if ((r = mpt_attach(pdev,id)) != 0)
                return r;
-       
+
        ioc = pci_get_drvdata(pdev);
        ioc->DoneCtx = mptfcDoneCtx;
        ioc->TaskCtx = mptfcTaskCtx;
@@ -194,7 +669,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                printk(MYIOC_s_WARN_FMT
                        "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
                        ioc->name, ioc);
-               return 0;
+               return -ENODEV;
        }
 
        sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -207,6 +682,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_mptfc_probe;
         }
 
+       INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices,(void *)ioc);
+
        spin_lock_irqsave(&ioc->FreeQlock, flags);
 
        /* Attach the SCSI Host to the IOC structure
@@ -268,36 +745,27 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
-       sz = ioc->req_depth * sizeof(void *);
-       mem = kmalloc(sz, GFP_ATOMIC);
-       if (mem == NULL) {
+       hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+       if (!hd->ScsiLookup) {
                error = -ENOMEM;
                goto out_mptfc_probe;
        }
 
-       memset(mem, 0, sz);
-       hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-                ioc->name, hd->ScsiLookup, sz));
+       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+                ioc->name, hd->ScsiLookup));
 
        /* Allocate memory for the device structures.
         * A non-Null pointer at an offset
         * indicates a device exists.
         * max_id = 1 + maximum id (hosts.h)
         */
-       sz = sh->max_id * sizeof(void *);
-       mem = kmalloc(sz, GFP_ATOMIC);
-       if (mem == NULL) {
+       hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
+       if (!hd->Targets) {
                error = -ENOMEM;
                goto out_mptfc_probe;
        }
 
-       memset(mem, 0, sz);
-       hd->Targets = (VirtTarget **) mem;
-
-       dprintk((KERN_INFO
-         "  vdev @ %p, sz=%d\n", hd->Targets, sz));
+       dprintk((KERN_INFO "  vdev @ %p\n", hd->Targets));
 
        /* Clear the TM flags
         */
@@ -332,6 +800,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        hd->scandv_wait_done = 0;
        hd->last_queue_full = 0;
 
+       sh->transportt = mptfc_transport_template;
        error = scsi_add_host (sh, &ioc->pcidev->dev);
        if(error) {
                dprintk((KERN_ERR MYNAM
@@ -339,7 +808,11 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_mptfc_probe;
        }
 
-       scsi_scan_host(sh);
+       for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+               mptfc_init_host_attr(ioc,ii);
+               mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+       }
+
        return 0;
 
 out_mptfc_probe:
@@ -352,7 +825,7 @@ static struct pci_driver mptfc_driver = {
        .name           = "mptfc",
        .id_table       = mptfc_pci_table,
        .probe          = mptfc_probe,
-       .remove         = __devexit_p(mptscsih_remove),
+       .remove         = __devexit_p(mptfc_remove),
        .shutdown       = mptscsih_shutdown,
 #ifdef CONFIG_PM
        .suspend        = mptscsih_suspend,
@@ -370,9 +843,20 @@ static struct pci_driver mptfc_driver = {
 static int __init
 mptfc_init(void)
 {
+       int error;
 
        show_mptmod_ver(my_NAME, my_VERSION);
 
+       /* sanity check module parameter */
+       if (mptfc_dev_loss_tmo == 0)
+               mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
+
+       mptfc_transport_template =
+               fc_attach_transport(&mptfc_transport_functions);
+
+       if (!mptfc_transport_template)
+               return -ENODEV;
+
        mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
        mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
        mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
@@ -387,7 +871,33 @@ mptfc_init(void)
                  ": Registered for IOC reset notifications\n"));
        }
 
-       return pci_register_driver(&mptfc_driver);
+       error = pci_register_driver(&mptfc_driver);
+       if (error) {
+               fc_release_transport(mptfc_transport_template);
+       }
+
+       return error;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *     mptfc_remove - Removed fc infrastructure for devices
+ *     @pdev: Pointer to pci_dev structure
+ *
+ */
+static void __devexit mptfc_remove(struct pci_dev *pdev)
+{
+       MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+       struct mptfc_rport_info *p, *n;
+
+       fc_remove_host(ioc->sh);
+
+       list_for_each_entry_safe(p, n, &ioc->fc_rports, list) {
+               list_del(&p->list);
+               kfree(p);
+       }
+
+       mptscsih_remove(pdev);
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -400,7 +910,8 @@ static void __exit
 mptfc_exit(void)
 {
        pci_unregister_driver(&mptfc_driver);
-       
+       fc_release_transport(mptfc_transport_template);
+
        mpt_reset_deregister(mptfcDoneCtx);
        dprintk((KERN_INFO MYNAM
          ": Deregistered for IOC reset notifications\n"));
index 014085d8ec85cfd370fb15b4add8f59e0015931b..73f59528212ae3aa92590eb6058457999afb3776 100644 (file)
@@ -411,14 +411,12 @@ mpt_lan_open(struct net_device *dev)
                goto out;
        priv->mpt_txfidx_tail = -1;
 
-       priv->SendCtl = kmalloc(priv->tx_max_out * sizeof(struct BufferControl),
+       priv->SendCtl = kcalloc(priv->tx_max_out, sizeof(struct BufferControl),
                                GFP_KERNEL);
        if (priv->SendCtl == NULL)
                goto out_mpt_txfidx;
-       for (i = 0; i < priv->tx_max_out; i++) {
-               memset(&priv->SendCtl[i], 0, sizeof(struct BufferControl));
+       for (i = 0; i < priv->tx_max_out; i++)
                priv->mpt_txfidx[++priv->mpt_txfidx_tail] = i;
-       }
 
        dlprintk((KERN_INFO MYNAM "@lo: Finished initializing SendCtl\n"));
 
@@ -428,15 +426,13 @@ mpt_lan_open(struct net_device *dev)
                goto out_SendCtl;
        priv->mpt_rxfidx_tail = -1;
 
-       priv->RcvCtl = kmalloc(priv->max_buckets_out *
-                                               sizeof(struct BufferControl),
+       priv->RcvCtl = kcalloc(priv->max_buckets_out,
+                              sizeof(struct BufferControl),
                               GFP_KERNEL);
        if (priv->RcvCtl == NULL)
                goto out_mpt_rxfidx;
-       for (i = 0; i < priv->max_buckets_out; i++) {
-               memset(&priv->RcvCtl[i], 0, sizeof(struct BufferControl));
+       for (i = 0; i < priv->max_buckets_out; i++)
                priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = i;
-       }
 
 /**/   dlprintk((KERN_INFO MYNAM "/lo: txfidx contains - "));
 /**/   for (i = 0; i < priv->tx_max_out; i++)
@@ -848,7 +844,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline void
+static void
 mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
 /*
  * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue
@@ -870,7 +866,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority)
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static inline int
+static int
 mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
 {
        struct mpt_lan_priv *priv = dev->priv;
index 17e9757e728be780211d1e7a0008aaa9e2724d18..5a06d8d8694eb3cff0322e479a089ffb5d7021c1 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  Copyright (c) 1999-2005 LSI Logic Corporation
  *  (mailto:mpt_linux_developer@lsil.com)
- *  Copyright (c) 2005 Dell
+ *  Copyright (c) 2005-2006 Dell
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -86,6 +86,24 @@ static int   mptsasInternalCtx = -1; /* Used only for internal commands */
 static int     mptsasMgmtCtx = -1;
 
 
+enum mptsas_hotplug_action {
+       MPTSAS_ADD_DEVICE,
+       MPTSAS_DEL_DEVICE,
+};
+
+struct mptsas_hotplug_event {
+       struct work_struct      work;
+       MPT_ADAPTER             *ioc;
+       enum mptsas_hotplug_action event_type;
+       u64                     sas_address;
+       u32                     channel;
+       u32                     id;
+       u32                     device_info;
+       u16                     handle;
+       u16                     parent_handle;
+       u8                      phy_id;
+};
+
 /*
  * SAS topology structures
  *
@@ -99,8 +117,8 @@ struct mptsas_devinfo {
        u8      phy_id;         /* phy number of parent device */
        u8      port_id;        /* sas physical port this device
                                   is assoc'd with */
-       u8      target;         /* logical target id of this device */
-       u8      bus;            /* logical bus number of this device */
+       u8      id;             /* logical target id of this device */
+       u8      channel;        /* logical bus number of this device */
        u64     sas_address;    /* WWN of this device,
                                   SATA is assigned by HBA,expander */
        u32     device_info;    /* bitfield detailed info about this device */
@@ -114,6 +132,7 @@ struct mptsas_phyinfo {
        u8      programmed_link_rate;   /* programmed max/min phy link rate */
        struct mptsas_devinfo identify; /* point to phy device info */
        struct mptsas_devinfo attached; /* point to attached device info */
+       struct sas_phy *phy;
        struct sas_rphy *rphy;
 };
 
@@ -239,13 +258,12 @@ mptsas_slave_alloc(struct scsi_device *sdev)
        struct scsi_target      *starget;
        int i;
 
-       vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+       vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
        if (!vdev) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
                                hd->ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
-       memset(vdev, 0, sizeof(VirtDevice));
        vdev->ioc_id = hd->ioc->id;
        sdev->hostdata = vdev;
        starget = scsi_target(sdev);
@@ -256,19 +274,32 @@ mptsas_slave_alloc(struct scsi_device *sdev)
                hd->Targets[sdev->id] = vtarget;
        }
 
+       /*
+         RAID volumes placed beyond the last expected port.
+       */
+       if (sdev->channel == hd->ioc->num_ports) {
+               vdev->target_id = sdev->id;
+               vdev->bus_id = 0;
+               vdev->lun = 0;
+               goto out;
+       }
+
        rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
+       mutex_lock(&hd->ioc->sas_topology_mutex);
        list_for_each_entry(p, &hd->ioc->sas_topology, list) {
                for (i = 0; i < p->num_phys; i++) {
                        if (p->phy_info[i].attached.sas_address ==
                                        rphy->identify.sas_address) {
                                vdev->target_id =
-                                       p->phy_info[i].attached.target;
-                               vdev->bus_id = p->phy_info[i].attached.bus;
+                                       p->phy_info[i].attached.id;
+                               vdev->bus_id = p->phy_info[i].attached.channel;
                                vdev->lun = sdev->lun;
+       mutex_unlock(&hd->ioc->sas_topology_mutex);
                                goto out;
                        }
                }
        }
+       mutex_unlock(&hd->ioc->sas_topology_mutex);
 
        printk("No matching SAS device found!!\n");
        kfree(vdev);
@@ -282,6 +313,42 @@ mptsas_slave_alloc(struct scsi_device *sdev)
        return 0;
 }
 
+static void
+mptsas_slave_destroy(struct scsi_device *sdev)
+{
+       struct Scsi_Host *host = sdev->host;
+       MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+       struct sas_rphy *rphy;
+       struct mptsas_portinfo *p;
+       int i;
+
+       /*
+        * Handle hotplug removal case.
+        * We need to clear out attached data structure.
+        */
+       rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
+
+       mutex_lock(&hd->ioc->sas_topology_mutex);
+       list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+               for (i = 0; i < p->num_phys; i++) {
+                       if (p->phy_info[i].attached.sas_address ==
+                                       rphy->identify.sas_address) {
+                               memset(&p->phy_info[i].attached, 0,
+                                   sizeof(struct mptsas_devinfo));
+                               p->phy_info[i].rphy = NULL;
+                               goto out;
+                       }
+               }
+       }
+
+ out:
+       mutex_unlock(&hd->ioc->sas_topology_mutex);
+       /*
+        * TODO: Issue target reset to flush firmware outstanding commands.
+        */
+       mptscsih_slave_destroy(sdev);
+}
+
 static struct scsi_host_template mptsas_driver_template = {
        .module                         = THIS_MODULE,
        .proc_name                      = "mptsas",
@@ -293,7 +360,7 @@ static struct scsi_host_template mptsas_driver_template = {
        .slave_alloc                    = mptsas_slave_alloc,
        .slave_configure                = mptscsih_slave_configure,
        .target_destroy                 = mptscsih_target_destroy,
-       .slave_destroy                  = mptscsih_slave_destroy,
+       .slave_destroy                  = mptsas_slave_destroy,
        .change_queue_depth             = mptscsih_change_queue_depth,
        .eh_abort_handler               = mptscsih_abort,
        .eh_device_reset_handler        = mptscsih_dev_reset,
@@ -399,7 +466,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
                return -ENXIO;
 
-       if (down_interruptible(&ioc->sas_mgmt.mutex))
+       if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
                goto out;
 
        mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
@@ -450,7 +517,7 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
        error = 0;
 
  out_unlock:
-       up(&ioc->sas_mgmt.mutex);
+       mutex_unlock(&ioc->sas_mgmt.mutex);
  out:
        return error;
 }
@@ -649,8 +716,8 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
        device_info->handle = le16_to_cpu(buffer->DevHandle);
        device_info->phy_id = buffer->PhyNum;
        device_info->port_id = buffer->PhysicalPort;
-       device_info->target = buffer->TargetID;
-       device_info->bus = buffer->Bus;
+       device_info->id = buffer->TargetID;
+       device_info->channel = buffer->Bus;
        memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
        device_info->sas_address = le64_to_cpu(sas_address);
        device_info->device_info =
@@ -858,36 +925,36 @@ mptsas_parse_device_info(struct sas_identify *identify,
 static int mptsas_probe_one_phy(struct device *dev,
                struct mptsas_phyinfo *phy_info, int index, int local)
 {
-       struct sas_phy *port;
+       struct sas_phy *phy;
        int error;
 
-       port = sas_phy_alloc(dev, index);
-       if (!port)
+       phy = sas_phy_alloc(dev, index);
+       if (!phy)
                return -ENOMEM;
 
-       port->port_identifier = phy_info->port_id;
-       mptsas_parse_device_info(&port->identify, &phy_info->identify);
+       phy->port_identifier = phy_info->port_id;
+       mptsas_parse_device_info(&phy->identify, &phy_info->identify);
 
        /*
         * Set Negotiated link rate.
         */
        switch (phy_info->negotiated_link_rate) {
        case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
-               port->negotiated_linkrate = SAS_PHY_DISABLED;
+               phy->negotiated_linkrate = SAS_PHY_DISABLED;
                break;
        case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
-               port->negotiated_linkrate = SAS_LINK_RATE_FAILED;
+               phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
                break;
        case MPI_SAS_IOUNIT0_RATE_1_5:
-               port->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+               phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
                break;
        case MPI_SAS_IOUNIT0_RATE_3_0:
-               port->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+               phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
                break;
        case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
        case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
        default:
-               port->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+               phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
                break;
        }
 
@@ -896,10 +963,10 @@ static int mptsas_probe_one_phy(struct device *dev,
         */
        switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
        case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
-               port->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+               phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
                break;
        case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
-               port->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+               phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
                break;
        default:
                break;
@@ -911,10 +978,10 @@ static int mptsas_probe_one_phy(struct device *dev,
        switch (phy_info->programmed_link_rate &
                        MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
        case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
-               port->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+               phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
                break;
        case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
-               port->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+               phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
                break;
        default:
                break;
@@ -925,10 +992,10 @@ static int mptsas_probe_one_phy(struct device *dev,
         */
        switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
        case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
-               port->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+               phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
                break;
        case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
-               port->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+               phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
                break;
        default:
                break;
@@ -940,28 +1007,29 @@ static int mptsas_probe_one_phy(struct device *dev,
        switch (phy_info->programmed_link_rate &
                        MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
        case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
-               port->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+               phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
                break;
        case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
-               port->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+               phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
                break;
        default:
                break;
        }
 
        if (local)
-               port->local_attached = 1;
+               phy->local_attached = 1;
 
-       error = sas_phy_add(port);
+       error = sas_phy_add(phy);
        if (error) {
-               sas_phy_free(port);
+               sas_phy_free(phy);
                return error;
        }
+       phy_info->phy = phy;
 
        if (phy_info->attached.handle) {
                struct sas_rphy *rphy;
 
-               rphy = sas_rphy_alloc(port);
+               rphy = sas_rphy_alloc(phy);
                if (!rphy)
                        return 0; /* non-fatal: an rphy can be added later */
 
@@ -985,16 +1053,19 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index)
        u32 handle = 0xFFFF;
        int error = -ENOMEM, i;
 
-       port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
+       port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
        if (!port_info)
                goto out;
-       memset(port_info, 0, sizeof(*port_info));
 
        error = mptsas_sas_io_unit_pg0(ioc, port_info);
        if (error)
                goto out_free_port_info;
 
+       ioc->num_ports = port_info->num_phys;
+       mutex_lock(&ioc->sas_topology_mutex);
        list_add_tail(&port_info->list, &ioc->sas_topology);
+       mutex_unlock(&ioc->sas_topology_mutex);
+
        for (i = 0; i < port_info->num_phys; i++) {
                mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
                        (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
@@ -1034,10 +1105,9 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
        struct mptsas_portinfo *port_info, *p;
        int error = -ENOMEM, i, j;
 
-       port_info = kmalloc(sizeof(*port_info), GFP_KERNEL);
+       port_info = kzalloc(sizeof(*port_info), GFP_KERNEL);
        if (!port_info)
                goto out;
-       memset(port_info, 0, sizeof(*port_info));
 
        error = mptsas_sas_expander_pg0(ioc, port_info,
                (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
@@ -1047,7 +1117,10 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
 
        *handle = port_info->handle;
 
+       mutex_lock(&ioc->sas_topology_mutex);
        list_add_tail(&port_info->list, &ioc->sas_topology);
+       mutex_unlock(&ioc->sas_topology_mutex);
+
        for (i = 0; i < port_info->num_phys; i++) {
                struct device *parent;
 
@@ -1079,6 +1152,7 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
                 * HBA phys.
                 */
                parent = &ioc->sh->shost_gendev;
+               mutex_lock(&ioc->sas_topology_mutex);
                list_for_each_entry(p, &ioc->sas_topology, list) {
                        for (j = 0; j < p->num_phys; j++) {
                                if (port_info->phy_info[i].identify.handle ==
@@ -1086,6 +1160,7 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index)
                                        parent = &p->phy_info[j].rphy->dev;
                        }
                }
+               mutex_unlock(&ioc->sas_topology_mutex);
 
                mptsas_probe_one_phy(parent, &port_info->phy_info[i],
                                     *index, 0);
@@ -1111,6 +1186,211 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
                ;
 }
 
+static struct mptsas_phyinfo *
+mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
+{
+       struct mptsas_portinfo *port_info;
+       struct mptsas_devinfo device_info;
+       struct mptsas_phyinfo *phy_info = NULL;
+       int i, error;
+
+       /*
+        * Retrieve the parent sas_address
+        */
+       error = mptsas_sas_device_pg0(ioc, &device_info,
+               (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
+                MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
+               parent_handle);
+       if (error) {
+               printk("mptsas: failed to retrieve device page\n");
+               return NULL;
+       }
+
+       /*
+        * The phy_info structures are never deallocated during lifetime of
+        * a host, so the code below is safe without additional refcounting.
+        */
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(port_info, &ioc->sas_topology, list) {
+               for (i = 0; i < port_info->num_phys; i++) {
+                       if (port_info->phy_info[i].identify.sas_address ==
+                           device_info.sas_address &&
+                           port_info->phy_info[i].phy_id == phy_id) {
+                               phy_info = &port_info->phy_info[i];
+                               break;
+                       }
+               }
+       }
+       mutex_unlock(&ioc->sas_topology_mutex);
+
+       return phy_info;
+}
+
+static struct mptsas_phyinfo *
+mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
+{
+       struct mptsas_portinfo *port_info;
+       struct mptsas_phyinfo *phy_info = NULL;
+       int i;
+
+       /*
+        * The phy_info structures are never deallocated during lifetime of
+        * a host, so the code below is safe without additional refcounting.
+        */
+       mutex_lock(&ioc->sas_topology_mutex);
+       list_for_each_entry(port_info, &ioc->sas_topology, list) {
+               for (i = 0; i < port_info->num_phys; i++) {
+                       if (port_info->phy_info[i].attached.handle == handle) {
+                               phy_info = &port_info->phy_info[i];
+                               break;
+                       }
+               }
+       }
+       mutex_unlock(&ioc->sas_topology_mutex);
+
+       return phy_info;
+}
+
+static void
+mptsas_hotplug_work(void *arg)
+{
+       struct mptsas_hotplug_event *ev = arg;
+       MPT_ADAPTER *ioc = ev->ioc;
+       struct mptsas_phyinfo *phy_info;
+       struct sas_rphy *rphy;
+       char *ds = NULL;
+
+       if (ev->device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
+               ds = "ssp";
+       if (ev->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET)
+               ds = "stp";
+       if (ev->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
+               ds = "sata";
+
+       switch (ev->event_type) {
+       case MPTSAS_DEL_DEVICE:
+               printk(MYIOC_s_INFO_FMT
+                      "removing %s device, channel %d, id %d, phy %d\n",
+                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
+
+               phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle);
+               if (!phy_info) {
+                       printk("mptsas: remove event for non-existant PHY.\n");
+                       break;
+               }
+
+               if (phy_info->rphy) {
+                       sas_rphy_delete(phy_info->rphy);
+                       phy_info->rphy = NULL;
+               }
+               break;
+       case MPTSAS_ADD_DEVICE:
+               printk(MYIOC_s_INFO_FMT
+                      "attaching %s device, channel %d, id %d, phy %d\n",
+                      ioc->name, ds, ev->channel, ev->id, ev->phy_id);
+
+               phy_info = mptsas_find_phyinfo_by_parent(ioc,
+                               ev->parent_handle, ev->phy_id);
+               if (!phy_info) {
+                       printk("mptsas: add event for non-existant PHY.\n");
+                       break;
+               }
+
+               if (phy_info->rphy) {
+                       printk("mptsas: trying to add existing device.\n");
+                       break;
+               }
+
+               /* fill attached info */
+               phy_info->attached.handle = ev->handle;
+               phy_info->attached.phy_id = ev->phy_id;
+               phy_info->attached.port_id = phy_info->identify.port_id;
+               phy_info->attached.id = ev->id;
+               phy_info->attached.channel = ev->channel;
+               phy_info->attached.sas_address = ev->sas_address;
+               phy_info->attached.device_info = ev->device_info;
+
+               rphy = sas_rphy_alloc(phy_info->phy);
+               if (!rphy)
+                       break; /* non-fatal: an rphy can be added later */
+
+               mptsas_parse_device_info(&rphy->identify, &phy_info->attached);
+               if (sas_rphy_add(rphy)) {
+                       sas_rphy_free(rphy);
+                       break;
+               }
+
+               phy_info->rphy = rphy;
+               break;
+       }
+
+       kfree(ev);
+}
+
+static void
+mptscsih_send_sas_event(MPT_ADAPTER *ioc,
+               EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
+{
+       struct mptsas_hotplug_event *ev;
+       u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
+       __le64 sas_address;
+
+       if ((device_info &
+            (MPI_SAS_DEVICE_INFO_SSP_TARGET |
+             MPI_SAS_DEVICE_INFO_STP_TARGET |
+             MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0)
+               return;
+
+       if ((sas_event_data->ReasonCode &
+            (MPI_EVENT_SAS_DEV_STAT_RC_ADDED |
+             MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING)) == 0)
+               return;
+
+       ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev) {
+               printk(KERN_WARNING "mptsas: lost hotplug event\n");
+               return;
+       }
+
+
+       INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
+       ev->ioc = ioc;
+       ev->handle = le16_to_cpu(sas_event_data->DevHandle);
+       ev->parent_handle = le16_to_cpu(sas_event_data->ParentDevHandle);
+       ev->channel = sas_event_data->Bus;
+       ev->id = sas_event_data->TargetID;
+       ev->phy_id = sas_event_data->PhyNum;
+       memcpy(&sas_address, &sas_event_data->SASAddress, sizeof(__le64));
+       ev->sas_address = le64_to_cpu(sas_address);
+       ev->device_info = device_info;
+
+       if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
+               ev->event_type = MPTSAS_ADD_DEVICE;
+       else
+               ev->event_type = MPTSAS_DEL_DEVICE;
+
+       schedule_work(&ev->work);
+}
+
+static int
+mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
+{
+       u8 event = le32_to_cpu(reply->Event) & 0xFF;
+
+       if (!ioc->sh)
+               return 1;
+
+       switch (event) {
+       case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
+               mptscsih_send_sas_event(ioc,
+                       (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
+               return 1;               /* currently means nothing really */
+
+       default:
+               return mptscsih_event_process(ioc, reply);
+       }
+}
+
 static int
 mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -1118,11 +1398,10 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        MPT_SCSI_HOST           *hd;
        MPT_ADAPTER             *ioc;
        unsigned long            flags;
-       int                      sz, ii;
+       int                      ii;
        int                      numSGE = 0;
        int                      scale;
        int                      ioc_cap;
-       u8                      *mem;
        int                     error=0;
        int                     r;
 
@@ -1203,7 +1482,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        sh->unique_id = ioc->id;
 
        INIT_LIST_HEAD(&ioc->sas_topology);
-       init_MUTEX(&ioc->sas_mgmt.mutex);
+       mutex_init(&ioc->sas_topology_mutex);
+
+       mutex_init(&ioc->sas_mgmt.mutex);
        init_completion(&ioc->sas_mgmt.done);
 
        /* Verify that we won't exceed the maximum
@@ -1244,36 +1525,27 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
-       sz = ioc->req_depth * sizeof(void *);
-       mem = kmalloc(sz, GFP_ATOMIC);
-       if (mem == NULL) {
+       hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+       if (!hd->ScsiLookup) {
                error = -ENOMEM;
                goto out_mptsas_probe;
        }
 
-       memset(mem, 0, sz);
-       hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-                ioc->name, hd->ScsiLookup, sz));
+       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+                ioc->name, hd->ScsiLookup));
 
        /* Allocate memory for the device structures.
         * A non-Null pointer at an offset
         * indicates a device exists.
         * max_id = 1 + maximum id (hosts.h)
         */
-       sz = sh->max_id * sizeof(void *);
-       mem = kmalloc(sz, GFP_ATOMIC);
-       if (mem == NULL) {
+       hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
+       if (!hd->Targets) {
                error = -ENOMEM;
                goto out_mptsas_probe;
        }
 
-       memset(mem, 0, sz);
-       hd->Targets = (VirtTarget **) mem;
-
-       dprintk((KERN_INFO
-         "  vtarget @ %p, sz=%d\n", hd->Targets, sz));
+       dprintk((KERN_INFO "  vtarget @ %p\n", hd->Targets));
 
        /* Clear the TM flags
         */
@@ -1324,6 +1596,20 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        mptsas_scan_sas_topology(ioc);
 
+       /*
+         Reporting RAID volumes.
+       */
+       if (!ioc->raid_data.pIocPg2)
+               return 0;
+       if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
+               return 0;
+       for (ii=0;ii<ioc->raid_data.pIocPg2->NumActiveVolumes;ii++) {
+               scsi_add_device(sh,
+                       ioc->num_ports,
+                       ioc->raid_data.pIocPg2->RaidVolume[ii].VolumeID,
+                       0);
+       }
+
        return 0;
 
 out_mptsas_probe:
@@ -1339,10 +1625,12 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
 
        sas_remove_host(ioc->sh);
 
+       mutex_lock(&ioc->sas_topology_mutex);
        list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
                list_del(&p->list);
                kfree(p);
        }
+       mutex_unlock(&ioc->sas_topology_mutex);
 
        mptscsih_remove(pdev);
 }
@@ -1393,7 +1681,7 @@ mptsas_init(void)
                mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
        mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
 
-       if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) {
+       if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
                devtprintk((KERN_INFO MYNAM
                  ": Registered for IOC event notifications\n"));
        }
index 93a16fa3c4baeab822056108f9e622e906b10d5c..cdac5578fdf220caefb48a3356710393558372ff 100644 (file)
@@ -893,6 +893,7 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
  *             when a lun is disable by mid-layer.
  *             Do NOT access the referenced scsi_cmnd structure or
  *             members. Will cause either a paging or NULL ptr error.
+ *             (BUT, BUT, BUT, the code does reference it! - mdr)
  *      @hd: Pointer to a SCSI HOST structure
  *     @vdevice: per device private data
  *
@@ -2162,10 +2163,9 @@ mptscsih_target_alloc(struct scsi_target *starget)
 {
        VirtTarget              *vtarget;
 
-       vtarget = kmalloc(sizeof(VirtTarget), GFP_KERNEL);
+       vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
        if (!vtarget)
                return -ENOMEM;
-       memset(vtarget, 0, sizeof(VirtTarget));
        starget->hostdata = vtarget;
        return 0;
 }
@@ -2185,14 +2185,13 @@ mptscsih_slave_alloc(struct scsi_device *sdev)
        VirtDevice              *vdev;
        struct scsi_target      *starget;
 
-       vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+       vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
        if (!vdev) {
                printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
                                hd->ioc->name, sizeof(VirtDevice));
                return -ENOMEM;
        }
 
-       memset(vdev, 0, sizeof(VirtDevice));
        vdev->ioc_id = hd->ioc->id;
        vdev->target_id = sdev->id;
        vdev->bus_id = sdev->channel;
@@ -2559,13 +2558,25 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
                        hd->cmdPtr = NULL;
                }
 
-               /* 7. Set flag to force DV and re-read IOC Page 3
+               /* 7. SPI: Set flag to force DV and re-read IOC Page 3
                 */
                if (ioc->bus_type == SPI) {
                        ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
                        ddvtprintk(("Set reload IOC Pg3 Flag\n"));
                }
 
+               /* 7. FC: Rescan for blocked rports which might have returned.
+                */
+               else if (ioc->bus_type == FC) {
+                       int work_count;
+                       unsigned long flags;
+
+                       spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+                       work_count = ++ioc->fc_rescan_work_count;
+                       spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+                       if (work_count == 1)
+                               schedule_work(&ioc->fc_rescan_work);
+               }
                dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
 
        }
@@ -2589,6 +2600,8 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
 {
        MPT_SCSI_HOST *hd;
        u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+       int work_count;
+       unsigned long flags;
 
        devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
                        ioc->name, event));
@@ -2610,11 +2623,18 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
                /* FIXME! */
                break;
 
+       case MPI_EVENT_RESCAN:                          /* 06 */
+               spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+               work_count = ++ioc->fc_rescan_work_count;
+               spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+               if (work_count == 1)
+                       schedule_work(&ioc->fc_rescan_work);
+               break;
+
                /*
                 *  CHECKME! Don't think we need to do
                 *  anything for these, but...
                 */
-       case MPI_EVENT_RESCAN:                          /* 06 */
        case MPI_EVENT_LINK_STATUS_CHANGE:              /* 07 */
        case MPI_EVENT_LOOP_STATE_CHANGE:               /* 08 */
                /*
@@ -3952,8 +3972,6 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
                mptscsih_do_cmd(hd, &iocmd);
 }
 
-/* Search IOC page 3 to determine if this is hidden physical disk
- */
 /* Search IOC page 3 to determine if this is hidden physical disk
  */
 static int
index ce332a6085e5345e2b64a259da1d44a04eec693d..7dce29277cb748e51e1ef8a3956f618cddc28818 100644 (file)
@@ -158,11 +158,10 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        MPT_SCSI_HOST           *hd;
        MPT_ADAPTER             *ioc;
        unsigned long            flags;
-       int                      sz, ii;
+       int                      ii;
        int                      numSGE = 0;
        int                      scale;
        int                      ioc_cap;
-       u8                      *mem;
        int                     error=0;
        int                     r;
 
@@ -288,36 +287,27 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        /* SCSI needs scsi_cmnd lookup table!
         * (with size equal to req_depth*PtrSz!)
         */
-       sz = ioc->req_depth * sizeof(void *);
-       mem = kmalloc(sz, GFP_ATOMIC);
-       if (mem == NULL) {
+       hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+       if (!hd->ScsiLookup) {
                error = -ENOMEM;
                goto out_mptspi_probe;
        }
 
-       memset(mem, 0, sz);
-       hd->ScsiLookup = (struct scsi_cmnd **) mem;
-
-       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n",
-                ioc->name, hd->ScsiLookup, sz));
+       dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+                ioc->name, hd->ScsiLookup));
 
        /* Allocate memory for the device structures.
         * A non-Null pointer at an offset
         * indicates a device exists.
         * max_id = 1 + maximum id (hosts.h)
         */
-       sz = sh->max_id * sizeof(void *);
-       mem = kmalloc(sz, GFP_ATOMIC);
-       if (mem == NULL) {
+       hd->Targets = kcalloc(sh->max_id, sizeof(void *), GFP_ATOMIC);
+       if (!hd->Targets) {
                error = -ENOMEM;
                goto out_mptspi_probe;
        }
 
-       memset(mem, 0, sz);
-       hd->Targets = (VirtTarget **) mem;
-
-       dprintk((KERN_INFO
-         "  vdev @ %p, sz=%d\n", hd->Targets, sz));
+       dprintk((KERN_INFO "  vdev @ %p\n", hd->Targets));
 
        /* Clear the TM flags
         */
index c5b656cdea7cf2b72a88267343a159deb01efd75..d698d7709c31c8d6073a58e3893de2c723f760f5 100644 (file)
@@ -88,11 +88,6 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
        struct device *dev = &pdev->dev;
        int i;
 
-       if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
-               printk(KERN_ERR "%s: device already claimed\n", c->name);
-               return -ENODEV;
-       }
-
        for (i = 0; i < 6; i++) {
                /* Skip I/O spaces */
                if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
@@ -319,6 +314,11 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
                return rc;
        }
 
+       if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+               printk(KERN_ERR "i2o: device already claimed\n");
+               return -ENODEV;
+       }
+
        if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
                printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
                       pci_name(pdev));
index 55ba23075c90ed688ad2ee88c9608a1fefcda77a..75f401d52fda117409468a431424fe9cc177c091 100644 (file)
@@ -77,6 +77,8 @@ static int mcp_bus_resume(struct device *dev)
 static struct bus_type mcp_bus_type = {
        .name           = "mcp",
        .match          = mcp_bus_match,
+       .probe          = mcp_bus_probe,
+       .remove         = mcp_bus_remove,
        .suspend        = mcp_bus_suspend,
        .resume         = mcp_bus_resume,
 };
@@ -227,8 +229,6 @@ EXPORT_SYMBOL(mcp_host_unregister);
 int mcp_driver_register(struct mcp_driver *mcpdrv)
 {
        mcpdrv->drv.bus = &mcp_bus_type;
-       mcpdrv->drv.probe = mcp_bus_probe;
-       mcpdrv->drv.remove = mcp_bus_remove;
        return driver_register(&mcpdrv->drv);
 }
 EXPORT_SYMBOL(mcp_driver_register);
index 9b7c37e0e5742c6731ceb4494bd2c48f04fc6b31..5b014c370e809dc5ecfd6acd57384f6f6295877c 100644 (file)
@@ -462,9 +462,10 @@ static int mmc_blk_probe(struct mmc_card *card)
        if (err)
                goto out;
 
-       printk(KERN_INFO "%s: %s %s %luKiB %s\n",
+       printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
                md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
-               get_capacity(md->disk) >> 1, md->read_only ? "(ro)" : "");
+               (unsigned long long)(get_capacity(md->disk) >> 1),
+               md->read_only ? "(ro)" : "");
 
        mmc_set_drvdata(card, md);
        add_disk(md->disk);
index ec701667abfc120cf3bcb15c9c8381513e29e3b4..a2a35fd946eecf8a2b9fc585b2687f39e2806e82 100644 (file)
@@ -136,17 +136,7 @@ static int mmc_bus_resume(struct device *dev)
        return ret;
 }
 
-static struct bus_type mmc_bus_type = {
-       .name           = "mmc",
-       .dev_attrs      = mmc_dev_attrs,
-       .match          = mmc_bus_match,
-       .uevent         = mmc_bus_uevent,
-       .suspend        = mmc_bus_suspend,
-       .resume         = mmc_bus_resume,
-};
-
-
-static int mmc_drv_probe(struct device *dev)
+static int mmc_bus_probe(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
        struct mmc_card *card = dev_to_mmc_card(dev);
@@ -154,7 +144,7 @@ static int mmc_drv_probe(struct device *dev)
        return drv->probe(card);
 }
 
-static int mmc_drv_remove(struct device *dev)
+static int mmc_bus_remove(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
        struct mmc_card *card = dev_to_mmc_card(dev);
@@ -164,6 +154,16 @@ static int mmc_drv_remove(struct device *dev)
        return 0;
 }
 
+static struct bus_type mmc_bus_type = {
+       .name           = "mmc",
+       .dev_attrs      = mmc_dev_attrs,
+       .match          = mmc_bus_match,
+       .uevent         = mmc_bus_uevent,
+       .probe          = mmc_bus_probe,
+       .remove         = mmc_bus_remove,
+       .suspend        = mmc_bus_suspend,
+       .resume         = mmc_bus_resume,
+};
 
 /**
  *     mmc_register_driver - register a media driver
@@ -172,8 +172,6 @@ static int mmc_drv_remove(struct device *dev)
 int mmc_register_driver(struct mmc_driver *drv)
 {
        drv->drv.bus = &mmc_bus_type;
-       drv->drv.probe = mmc_drv_probe;
-       drv->drv.remove = mmc_drv_remove;
        return driver_register(&drv->drv);
 }
 
index 9a2aa4033c6a6e37ea60ade60a4f67c70613ccc5..5038e90ceb1255d269c4b4054830317c0ffa8db4 100644 (file)
@@ -47,6 +47,22 @@ config MTD_MS02NV
          accelerator.  Say Y here if you have a DECstation 5000/2x0 or a
          DECsystem 5900 equipped with such a module.
 
+config MTD_DATAFLASH
+       tristate "Support for AT45xxx DataFlash"
+       depends on MTD && SPI_MASTER && EXPERIMENTAL
+       help
+         This enables access to AT45xxx DataFlash chips, using SPI.
+         Sometimes DataFlash chips are packaged inside MMC-format
+         cards; at this writing, the MMC stack won't handle those.
+
+config MTD_M25P80
+       tristate "Support for M25 SPI Flash"
+       depends on MTD && SPI_MASTER && EXPERIMENTAL
+       help
+         This enables access to ST M25P80 and similar SPI flash chips,
+         used for program and data storage.  Set up your spi devices
+         with the right board-specific platform data.
+
 config MTD_SLRAM
        tristate "Uncached system RAM"
        depends on MTD
index e38db348057d578af0394b901946296c65dfe52a..7c5ed2178380119b074f738ea14d5e6b5fd1e345 100644 (file)
@@ -23,3 +23,5 @@ obj-$(CONFIG_MTD_MTDRAM)      += mtdram.o
 obj-$(CONFIG_MTD_LART)         += lart.o
 obj-$(CONFIG_MTD_BLKMTD)       += blkmtd.o
 obj-$(CONFIG_MTD_BLOCK2MTD)    += block2mtd.o
+obj-$(CONFIG_MTD_DATAFLASH)    += mtd_dataflash.o
+obj-$(CONFIG_MTD_M25P80)       += m25p80.o
index be5e88b3888daf727404fa12c5cb22bb77b01b40..e4345cf744a22d5e927244b4a1fa8e135157a5a9 100644 (file)
@@ -138,7 +138,7 @@ static inline int DoC_WaitReady(struct DiskOnChip *doc)
    bypass the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
    required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
 
-static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
+static int DoC_Command(struct DiskOnChip *doc, unsigned char command,
                              unsigned char xtraflags)
 {
        void __iomem *docptr = doc->virtadr;
index fcb28a6fd89f8dc011698b828b0c046b23aeb382..681a9c73a2a321850404d4856f4738be47e17d15 100644 (file)
@@ -103,7 +103,7 @@ static inline int DoC_WaitReady(void __iomem * docptr)
    with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
    required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
 
-static inline void DoC_Command(void __iomem * docptr, unsigned char command,
+static void DoC_Command(void __iomem * docptr, unsigned char command,
                               unsigned char xtraflags)
 {
        /* Assert the CLE (Command Latch Enable) line to the flash chip */
index 0595cc7324b257d7f95a147c618df5af9f6bf73f..5f57f29efee48d84e235a8ff75a35e7e354227a7 100644 (file)
@@ -118,7 +118,7 @@ static inline void DoC_CheckASIC(void __iomem * docptr)
 /* DoC_Command: Send a flash command to the flash chip through the Flash
  * command register. Need 2 Write Pipeline Terminates to complete send.
  */
-static inline void DoC_Command(void __iomem * docptr, unsigned char command,
+static void DoC_Command(void __iomem * docptr, unsigned char command,
                               unsigned char xtraflags)
 {
        WriteDOC(command, docptr, Mplus_FlashCmd);
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
new file mode 100644 (file)
index 0000000..d5f2408
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * MTD SPI driver for ST M25Pxx flash chips
+ *
+ * Author: Mike Lavender, mike@steroidmicros.com
+ *
+ * Copyright (c) 2005, Intec Automation Inc.
+ *
+ * Some parts are based on lart.c by Abraham Van Der Merwe
+ *
+ * Cleaned up and generalized based on mtd_dataflash.c
+ *
+ * This code 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/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <asm/semaphore.h>
+
+
+/* NOTE: AT 25F and SST 25LF series are very similar,
+ * but commands for sector erase and chip id differ...
+ */
+
+#define FLASH_PAGESIZE         256
+
+/* Flash opcodes. */
+#define        OPCODE_WREN             6       /* Write enable */
+#define        OPCODE_RDSR             5       /* Read status register */
+#define        OPCODE_READ             3       /* Read data bytes */
+#define        OPCODE_PP               2       /* Page program */
+#define        OPCODE_SE               0xd8    /* Sector erase */
+#define        OPCODE_RES              0xab    /* Read Electronic Signature */
+#define        OPCODE_RDID             0x9f    /* Read JEDEC ID */
+
+/* Status Register bits. */
+#define        SR_WIP                  1       /* Write in progress */
+#define        SR_WEL                  2       /* Write enable latch */
+#define        SR_BP0                  4       /* Block protect 0 */
+#define        SR_BP1                  8       /* Block protect 1 */
+#define        SR_BP2                  0x10    /* Block protect 2 */
+#define        SR_SRWD                 0x80    /* SR write protect */
+
+/* Define max times to check status register before we give up. */
+#define        MAX_READY_WAIT_COUNT    100000
+
+
+#ifdef CONFIG_MTD_PARTITIONS
+#define        mtd_has_partitions()    (1)
+#else
+#define        mtd_has_partitions()    (0)
+#endif
+
+/****************************************************************************/
+
+struct m25p {
+       struct spi_device       *spi;
+       struct semaphore        lock;
+       struct mtd_info         mtd;
+       unsigned                partitioned;
+       u8                      command[4];
+};
+
+static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
+{
+       return container_of(mtd, struct m25p, mtd);
+}
+
+/****************************************************************************/
+
+/*
+ * Internal helper functions
+ */
+
+/*
+ * Read the status register, returning its value in the location
+ * Return the status register value.
+ * Returns negative if error occurred.
+ */
+static int read_sr(struct m25p *flash)
+{
+       ssize_t retval;
+       u8 code = OPCODE_RDSR;
+       u8 val;
+
+       retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
+
+       if (retval < 0) {
+               dev_err(&flash->spi->dev, "error %d reading SR\n",
+                               (int) retval);
+               return retval;
+       }
+
+       return val;
+}
+
+
+/*
+ * Set write enable latch with Write Enable command.
+ * Returns negative if error occurred.
+ */
+static inline int write_enable(struct m25p *flash)
+{
+       u8      code = OPCODE_WREN;
+
+       return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+}
+
+
+/*
+ * Service routine to read status register until ready, or timeout occurs.
+ * Returns non-zero if error.
+ */
+static int wait_till_ready(struct m25p *flash)
+{
+       int count;
+       int sr;
+
+       /* one chip guarantees max 5 msec wait here after page writes,
+        * but potentially three seconds (!) after page erase.
+        */
+       for (count = 0; count < MAX_READY_WAIT_COUNT; count++) {
+               if ((sr = read_sr(flash)) < 0)
+                       break;
+               else if (!(sr & SR_WIP))
+                       return 0;
+
+               /* REVISIT sometimes sleeping would be best */
+       }
+
+       return 1;
+}
+
+
+/*
+ * Erase one sector of flash memory at offset ``offset'' which is any
+ * address within the sector which should be erased.
+ *
+ * Returns 0 if successful, non-zero otherwise.
+ */
+static int erase_sector(struct m25p *flash, u32 offset)
+{
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id,
+                       __FUNCTION__, offset);
+
+       /* Wait until finished previous write command. */
+       if (wait_till_ready(flash))
+               return 1;
+
+       /* Send write enable, then erase commands. */
+       write_enable(flash);
+
+       /* Set up command buffer. */
+       flash->command[0] = OPCODE_SE;
+       flash->command[1] = offset >> 16;
+       flash->command[2] = offset >> 8;
+       flash->command[3] = offset;
+
+       spi_write(flash->spi, flash->command, sizeof(flash->command));
+
+       return 0;
+}
+
+/****************************************************************************/
+
+/*
+ * MTD implementation
+ */
+
+/*
+ * Erase an address range on the flash chip.  The address range may extend
+ * one or more erase sectors.  Return an error is there is a problem erasing.
+ */
+static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       u32 addr,len;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+                       flash->spi->dev.bus_id, __FUNCTION__, "at",
+                       (u32)instr->addr, instr->len);
+
+       /* sanity checks */
+       if (instr->addr + instr->len > flash->mtd.size)
+               return -EINVAL;
+       if ((instr->addr % mtd->erasesize) != 0
+                       || (instr->len % mtd->erasesize) != 0) {
+               return -EINVAL;
+       }
+
+       addr = instr->addr;
+       len = instr->len;
+
+       down(&flash->lock);
+
+       /* now erase those sectors */
+       while (len) {
+               if (erase_sector(flash, addr)) {
+                       instr->state = MTD_ERASE_FAILED;
+                       up(&flash->lock);
+                       return -EIO;
+               }
+
+               addr += mtd->erasesize;
+               len -= mtd->erasesize;
+       }
+
+       up(&flash->lock);
+
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+
+       return 0;
+}
+
+/*
+ * Read an address range from the flash chip.  The address range
+ * may be any size provided it is within the physical boundaries.
+ */
+static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
+       size_t *retlen, u_char *buf)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       struct spi_transfer t[2];
+       struct spi_message m;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+                       flash->spi->dev.bus_id, __FUNCTION__, "from",
+                       (u32)from, len);
+
+       /* sanity checks */
+       if (!len)
+               return 0;
+
+       if (from + len > flash->mtd.size)
+               return -EINVAL;
+
+       spi_message_init(&m);
+       memset(t, 0, (sizeof t));
+
+       t[0].tx_buf = flash->command;
+       t[0].len = sizeof(flash->command);
+       spi_message_add_tail(&t[0], &m);
+
+       t[1].rx_buf = buf;
+       t[1].len = len;
+       spi_message_add_tail(&t[1], &m);
+
+       /* Byte count starts at zero. */
+       if (retlen)
+               *retlen = 0;
+
+       down(&flash->lock);
+
+       /* Wait till previous write/erase is done. */
+       if (wait_till_ready(flash)) {
+               /* REVISIT status return?? */
+               up(&flash->lock);
+               return 1;
+       }
+
+       /* NOTE:  OPCODE_FAST_READ (if available) is faster... */
+
+       /* Set up the write data buffer. */
+       flash->command[0] = OPCODE_READ;
+       flash->command[1] = from >> 16;
+       flash->command[2] = from >> 8;
+       flash->command[3] = from;
+
+       spi_sync(flash->spi, &m);
+
+       *retlen = m.actual_length - sizeof(flash->command);
+
+       up(&flash->lock);
+
+       return 0;
+}
+
+/*
+ * Write an address range to the flash chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
+ */
+static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       u32 page_offset, page_size;
+       struct spi_transfer t[2];
+       struct spi_message m;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
+                       flash->spi->dev.bus_id, __FUNCTION__, "to",
+                       (u32)to, len);
+
+       if (retlen)
+               *retlen = 0;
+
+       /* sanity checks */
+       if (!len)
+               return(0);
+
+       if (to + len > flash->mtd.size)
+               return -EINVAL;
+
+       spi_message_init(&m);
+       memset(t, 0, (sizeof t));
+
+       t[0].tx_buf = flash->command;
+       t[0].len = sizeof(flash->command);
+       spi_message_add_tail(&t[0], &m);
+
+       t[1].tx_buf = buf;
+       spi_message_add_tail(&t[1], &m);
+
+       down(&flash->lock);
+
+       /* Wait until finished previous write command. */
+       if (wait_till_ready(flash))
+               return 1;
+
+       write_enable(flash);
+
+       /* Set up the opcode in the write buffer. */
+       flash->command[0] = OPCODE_PP;
+       flash->command[1] = to >> 16;
+       flash->command[2] = to >> 8;
+       flash->command[3] = to;
+
+       /* what page do we start with? */
+       page_offset = to % FLASH_PAGESIZE;
+
+       /* do all the bytes fit onto one page? */
+       if (page_offset + len <= FLASH_PAGESIZE) {
+               t[1].len = len;
+
+               spi_sync(flash->spi, &m);
+
+               *retlen = m.actual_length - sizeof(flash->command);
+       } else {
+               u32 i;
+
+               /* the size of data remaining on the first page */
+               page_size = FLASH_PAGESIZE - page_offset;
+
+               t[1].len = page_size;
+               spi_sync(flash->spi, &m);
+
+               *retlen = m.actual_length - sizeof(flash->command);
+
+               /* write everything in PAGESIZE chunks */
+               for (i = page_size; i < len; i += page_size) {
+                       page_size = len - i;
+                       if (page_size > FLASH_PAGESIZE)
+                               page_size = FLASH_PAGESIZE;
+
+                       /* write the next page to flash */
+                       flash->command[1] = (to + i) >> 16;
+                       flash->command[2] = (to + i) >> 8;
+                       flash->command[3] = (to + i);
+
+                       t[1].tx_buf = buf + i;
+                       t[1].len = page_size;
+
+                       wait_till_ready(flash);
+
+                       write_enable(flash);
+
+                       spi_sync(flash->spi, &m);
+
+                       if (retlen)
+                               *retlen += m.actual_length
+                                       - sizeof(flash->command);
+               }
+       }
+
+       up(&flash->lock);
+
+       return 0;
+}
+
+
+/****************************************************************************/
+
+/*
+ * SPI device driver setup and teardown
+ */
+
+struct flash_info {
+       char            *name;
+       u8              id;
+       u16             jedec_id;
+       unsigned        sector_size;
+       unsigned        n_sectors;
+};
+
+static struct flash_info __devinitdata m25p_data [] = {
+       /* REVISIT: fill in JEDEC ids, for parts that have them */
+       { "m25p05", 0x05, 0x0000, 32 * 1024, 2 },
+       { "m25p10", 0x10, 0x0000, 32 * 1024, 4 },
+       { "m25p20", 0x11, 0x0000, 64 * 1024, 4 },
+       { "m25p40", 0x12, 0x0000, 64 * 1024, 8 },
+       { "m25p80", 0x13, 0x0000, 64 * 1024, 16 },
+       { "m25p16", 0x14, 0x0000, 64 * 1024, 32 },
+       { "m25p32", 0x15, 0x0000, 64 * 1024, 64 },
+       { "m25p64", 0x16, 0x2017, 64 * 1024, 128 },
+};
+
+/*
+ * board specific setup should have ensured the SPI clock used here
+ * matches what the READ command supports, at least until this driver
+ * understands FAST_READ (for clocks over 25 MHz).
+ */
+static int __devinit m25p_probe(struct spi_device *spi)
+{
+       struct flash_platform_data      *data;
+       struct m25p                     *flash;
+       struct flash_info               *info;
+       unsigned                        i;
+
+       /* Platform data helps sort out which chip type we have, as
+        * well as how this board partitions it.
+        */
+       data = spi->dev.platform_data;
+       if (!data || !data->type) {
+               /* FIXME some chips can identify themselves with RES
+                * or JEDEC get-id commands.  Try them ...
+                */
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n",
+                               flash->spi->dev.bus_id);
+               return -ENODEV;
+       }
+
+       for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) {
+               if (strcmp(data->type, info->name) == 0)
+                       break;
+       }
+       if (i == ARRAY_SIZE(m25p_data)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n",
+                               flash->spi->dev.bus_id, data->type);
+               return -ENODEV;
+       }
+
+       flash = kzalloc(sizeof *flash, SLAB_KERNEL);
+       if (!flash)
+               return -ENOMEM;
+
+       flash->spi = spi;
+       init_MUTEX(&flash->lock);
+       dev_set_drvdata(&spi->dev, flash);
+
+       if (data->name)
+               flash->mtd.name = data->name;
+       else
+               flash->mtd.name = spi->dev.bus_id;
+
+       flash->mtd.type = MTD_NORFLASH;
+       flash->mtd.flags = MTD_CAP_NORFLASH;
+       flash->mtd.size = info->sector_size * info->n_sectors;
+       flash->mtd.erasesize = info->sector_size;
+       flash->mtd.erase = m25p80_erase;
+       flash->mtd.read = m25p80_read;
+       flash->mtd.write = m25p80_write;
+
+       dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,
+                       flash->mtd.size / 1024);
+
+       DEBUG(MTD_DEBUG_LEVEL2,
+               "mtd .name = %s, .size = 0x%.8x (%uM) "
+                       ".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n",
+               flash->mtd.name,
+               flash->mtd.size, flash->mtd.size / (1024*1024),
+               flash->mtd.erasesize, flash->mtd.erasesize / 1024,
+               flash->mtd.numeraseregions);
+
+       if (flash->mtd.numeraseregions)
+               for (i = 0; i < flash->mtd.numeraseregions; i++)
+                       DEBUG(MTD_DEBUG_LEVEL2,
+                               "mtd.eraseregions[%d] = { .offset = 0x%.8x, "
+                               ".erasesize = 0x%.8x (%uK), "
+                               ".numblocks = %d }\n",
+                               i, flash->mtd.eraseregions[i].offset,
+                               flash->mtd.eraseregions[i].erasesize,
+                               flash->mtd.eraseregions[i].erasesize / 1024,
+                               flash->mtd.eraseregions[i].numblocks);
+
+
+       /* partitions should match sector boundaries; and it may be good to
+        * use readonly partitions for writeprotected sectors (BP2..BP0).
+        */
+       if (mtd_has_partitions()) {
+               struct mtd_partition    *parts = NULL;
+               int                     nr_parts = 0;
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+               static const char *part_probes[] = { "cmdlinepart", NULL, };
+
+               nr_parts = parse_mtd_partitions(&flash->mtd,
+                               part_probes, &parts, 0);
+#endif
+
+               if (nr_parts <= 0 && data && data->parts) {
+                       parts = data->parts;
+                       nr_parts = data->nr_parts;
+               }
+
+               if (nr_parts > 0) {
+                       for (i = 0; i < data->nr_parts; i++) {
+                               DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
+                                       "{.name = %s, .offset = 0x%.8x, "
+                                               ".size = 0x%.8x (%uK) }\n",
+                                       i, data->parts[i].name,
+                                       data->parts[i].offset,
+                                       data->parts[i].size,
+                                       data->parts[i].size / 1024);
+                       }
+                       flash->partitioned = 1;
+                       return add_mtd_partitions(&flash->mtd, parts, nr_parts);
+               }
+       } else if (data->nr_parts)
+               dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
+                               data->nr_parts, data->name);
+
+       return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
+}
+
+
+static int __devexit m25p_remove(struct spi_device *spi)
+{
+       struct m25p     *flash = dev_get_drvdata(&spi->dev);
+       int             status;
+
+       /* Clean up MTD stuff. */
+       if (mtd_has_partitions() && flash->partitioned)
+               status = del_mtd_partitions(&flash->mtd);
+       else
+               status = del_mtd_device(&flash->mtd);
+       if (status == 0)
+               kfree(flash);
+       return 0;
+}
+
+
+static struct spi_driver m25p80_driver = {
+       .driver = {
+               .name   = "m25p80",
+               .bus    = &spi_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = m25p_probe,
+       .remove = __devexit_p(m25p_remove),
+};
+
+
+static int m25p80_init(void)
+{
+       return spi_register_driver(&m25p80_driver);
+}
+
+
+static void m25p80_exit(void)
+{
+       spi_unregister_driver(&m25p80_driver);
+}
+
+
+module_init(m25p80_init);
+module_exit(m25p80_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Lavender");
+MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
new file mode 100644 (file)
index 0000000..155737e
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * Atmel AT45xxx DataFlash MTD driver for lightweight SPI framework
+ *
+ * Largely derived from at91_dataflash.c:
+ *  Copyright (C) 2003-2005 SAN People (Pty) 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/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+
+/*
+ * DataFlash is a kind of SPI flash.  Most AT45 chips have two buffers in
+ * each chip, which may be used for double buffered I/O; but this driver
+ * doesn't (yet) use these for any kind of i/o overlap or prefetching.
+ *
+ * Sometimes DataFlash is packaged in MMC-format cards, although the
+ * MMC stack can't use SPI (yet), or distinguish between MMC and DataFlash
+ * protocols during enumeration.
+ */
+
+#define CONFIG_DATAFLASH_WRITE_VERIFY
+
+/* reads can bypass the buffers */
+#define OP_READ_CONTINUOUS     0xE8
+#define OP_READ_PAGE           0xD2
+
+/* group B requests can run even while status reports "busy" */
+#define OP_READ_STATUS         0xD7    /* group B */
+
+/* move data between host and buffer */
+#define OP_READ_BUFFER1                0xD4    /* group B */
+#define OP_READ_BUFFER2                0xD6    /* group B */
+#define OP_WRITE_BUFFER1       0x84    /* group B */
+#define OP_WRITE_BUFFER2       0x87    /* group B */
+
+/* erasing flash */
+#define OP_ERASE_PAGE          0x81
+#define OP_ERASE_BLOCK         0x50
+
+/* move data between buffer and flash */
+#define OP_TRANSFER_BUF1       0x53
+#define OP_TRANSFER_BUF2       0x55
+#define OP_MREAD_BUFFER1       0xD4
+#define OP_MREAD_BUFFER2       0xD6
+#define OP_MWERASE_BUFFER1     0x83
+#define OP_MWERASE_BUFFER2     0x86
+#define OP_MWRITE_BUFFER1      0x88    /* sector must be pre-erased */
+#define OP_MWRITE_BUFFER2      0x89    /* sector must be pre-erased */
+
+/* write to buffer, then write-erase to flash */
+#define OP_PROGRAM_VIA_BUF1    0x82
+#define OP_PROGRAM_VIA_BUF2    0x85
+
+/* compare buffer to flash */
+#define OP_COMPARE_BUF1                0x60
+#define OP_COMPARE_BUF2                0x61
+
+/* read flash to buffer, then write-erase to flash */
+#define OP_REWRITE_VIA_BUF1    0x58
+#define OP_REWRITE_VIA_BUF2    0x59
+
+/* newer chips report JEDEC manufacturer and device IDs; chip
+ * serial number and OTP bits; and per-sector writeprotect.
+ */
+#define OP_READ_ID             0x9F
+#define OP_READ_SECURITY       0x77
+#define OP_WRITE_SECURITY      0x9A    /* OTP bits */
+
+
+struct dataflash {
+       u8                      command[4];
+       char                    name[24];
+
+       unsigned                partitioned:1;
+
+       unsigned short          page_offset;    /* offset in flash address */
+       unsigned int            page_size;      /* of bytes per page */
+
+       struct semaphore        lock;
+       struct spi_device       *spi;
+
+       struct mtd_info         mtd;
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+#define        mtd_has_partitions()    (1)
+#else
+#define        mtd_has_partitions()    (0)
+#endif
+
+/* ......................................................................... */
+
+/*
+ * Return the status of the DataFlash device.
+ */
+static inline int dataflash_status(struct spi_device *spi)
+{
+       /* NOTE:  at45db321c over 25 MHz wants to write
+        * a dummy byte after the opcode...
+        */
+       return spi_w8r8(spi, OP_READ_STATUS);
+}
+
+/*
+ * Poll the DataFlash device until it is READY.
+ * This usually takes 5-20 msec or so; more for sector erase.
+ */
+static int dataflash_waitready(struct spi_device *spi)
+{
+       int     status;
+
+       for (;;) {
+               status = dataflash_status(spi);
+               if (status < 0) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n",
+                                       spi->dev.bus_id, status);
+                       status = 0;
+               }
+
+               if (status & (1 << 7))  /* RDY/nBSY */
+                       return status;
+
+               msleep(3);
+       }
+}
+
+/* ......................................................................... */
+
+/*
+ * Erase pages of flash.
+ */
+static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct dataflash        *priv = (struct dataflash *)mtd->priv;
+       struct spi_device       *spi = priv->spi;
+       struct spi_transfer     x = { .tx_dma = 0, };
+       struct spi_message      msg;
+       unsigned                blocksize = priv->page_size << 3;
+       u8                      *command;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n",
+                       spi->dev.bus_id,
+                       instr->addr, instr->len);
+
+       /* Sanity checks */
+       if ((instr->addr + instr->len) > mtd->size
+                       || (instr->len % priv->page_size) != 0
+                       || (instr->addr % priv->page_size) != 0)
+               return -EINVAL;
+
+       spi_message_init(&msg);
+
+       x.tx_buf = command = priv->command;
+       x.len = 4;
+       spi_message_add_tail(&x, &msg);
+
+       down(&priv->lock);
+       while (instr->len > 0) {
+               unsigned int    pageaddr;
+               int             status;
+               int             do_block;
+
+               /* Calculate flash page address; use block erase (for speed) if
+                * we're at a block boundary and need to erase the whole block.
+                */
+               pageaddr = instr->addr / priv->page_size;
+               do_block = (pageaddr & 0x7) == 0 && instr->len <= blocksize;
+               pageaddr = pageaddr << priv->page_offset;
+
+               command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
+               command[1] = (u8)(pageaddr >> 16);
+               command[2] = (u8)(pageaddr >> 8);
+               command[3] = 0;
+
+               DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n",
+                       do_block ? "block" : "page",
+                       command[0], command[1], command[2], command[3],
+                       pageaddr);
+
+               status = spi_sync(spi, &msg);
+               (void) dataflash_waitready(spi);
+
+               if (status < 0) {
+                       printk(KERN_ERR "%s: erase %x, err %d\n",
+                               spi->dev.bus_id, pageaddr, status);
+                       /* REVISIT:  can retry instr->retries times; or
+                        * giveup and instr->fail_addr = instr->addr;
+                        */
+                       continue;
+               }
+
+               if (do_block) {
+                       instr->addr += blocksize;
+                       instr->len -= blocksize;
+               } else {
+                       instr->addr += priv->page_size;
+                       instr->len -= priv->page_size;
+               }
+       }
+       up(&priv->lock);
+
+       /* Inform MTD subsystem that erase is complete */
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+
+       return 0;
+}
+
+/*
+ * Read from the DataFlash device.
+ *   from   : Start offset in flash device
+ *   len    : Amount to read
+ *   retlen : About of data actually read
+ *   buf    : Buffer containing the data
+ */
+static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
+                              size_t *retlen, u_char *buf)
+{
+       struct dataflash        *priv = (struct dataflash *)mtd->priv;
+       struct spi_transfer     x[2] = { { .tx_dma = 0, }, };
+       struct spi_message      msg;
+       unsigned int            addr;
+       u8                      *command;
+       int                     status;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n",
+               priv->spi->dev.bus_id, (unsigned)from, (unsigned)(from + len));
+
+       *retlen = 0;
+
+       /* Sanity checks */
+       if (!len)
+               return 0;
+       if (from + len > mtd->size)
+               return -EINVAL;
+
+       /* Calculate flash page/byte address */
+       addr = (((unsigned)from / priv->page_size) << priv->page_offset)
+               + ((unsigned)from % priv->page_size);
+
+       command = priv->command;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n",
+               command[0], command[1], command[2], command[3]);
+
+       spi_message_init(&msg);
+
+       x[0].tx_buf = command;
+       x[0].len = 8;
+       spi_message_add_tail(&x[0], &msg);
+
+       x[1].rx_buf = buf;
+       x[1].len = len;
+       spi_message_add_tail(&x[1], &msg);
+
+       down(&priv->lock);
+
+       /* Continuous read, max clock = f(car) which may be less than
+        * the peak rate available.  Some chips support commands with
+        * fewer "don't care" bytes.  Both buffers stay unchanged.
+        */
+       command[0] = OP_READ_CONTINUOUS;
+       command[1] = (u8)(addr >> 16);
+       command[2] = (u8)(addr >> 8);
+       command[3] = (u8)(addr >> 0);
+       /* plus 4 "don't care" bytes */
+
+       status = spi_sync(priv->spi, &msg);
+       up(&priv->lock);
+
+       if (status >= 0) {
+               *retlen = msg.actual_length - 8;
+               status = 0;
+       } else
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n",
+                       priv->spi->dev.bus_id,
+                       (unsigned)from, (unsigned)(from + len),
+                       status);
+       return status;
+}
+
+/*
+ * Write to the DataFlash device.
+ *   to     : Start offset in flash device
+ *   len    : Amount to write
+ *   retlen : Amount of data actually written
+ *   buf    : Buffer containing the data
+ */
+static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
+                               size_t * retlen, const u_char * buf)
+{
+       struct dataflash        *priv = (struct dataflash *)mtd->priv;
+       struct spi_device       *spi = priv->spi;
+       struct spi_transfer     x[2] = { { .tx_dma = 0, }, };
+       struct spi_message      msg;
+       unsigned int            pageaddr, addr, offset, writelen;
+       size_t                  remaining = len;
+       u_char                  *writebuf = (u_char *) buf;
+       int                     status = -EINVAL;
+       u8                      *command;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n",
+               spi->dev.bus_id, (unsigned)to, (unsigned)(to + len));
+
+       *retlen = 0;
+
+       /* Sanity checks */
+       if (!len)
+               return 0;
+       if ((to + len) > mtd->size)
+               return -EINVAL;
+
+       spi_message_init(&msg);
+
+       x[0].tx_buf = command = priv->command;
+       x[0].len = 4;
+       spi_message_add_tail(&x[0], &msg);
+
+       pageaddr = ((unsigned)to / priv->page_size);
+       offset = ((unsigned)to % priv->page_size);
+       if (offset + len > priv->page_size)
+               writelen = priv->page_size - offset;
+       else
+               writelen = len;
+
+       down(&priv->lock);
+       while (remaining > 0) {
+               DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",
+                       pageaddr, offset, writelen);
+
+               /* REVISIT:
+                * (a) each page in a sector must be rewritten at least
+                *     once every 10K sibling erase/program operations.
+                * (b) for pages that are already erased, we could
+                *     use WRITE+MWRITE not PROGRAM for ~30% speedup.
+                * (c) WRITE to buffer could be done while waiting for
+                *     a previous MWRITE/MWERASE to complete ...
+                * (d) error handling here seems to be mostly missing.
+                *
+                * Two persistent bits per page, plus a per-sector counter,
+                * could support (a) and (b) ... we might consider using
+                * the second half of sector zero, which is just one block,
+                * to track that state.  (On AT91, that sector should also
+                * support boot-from-DataFlash.)
+                */
+
+               addr = pageaddr << priv->page_offset;
+
+               /* (1) Maybe transfer partial page to Buffer1 */
+               if (writelen != priv->page_size) {
+                       command[0] = OP_TRANSFER_BUF1;
+                       command[1] = (addr & 0x00FF0000) >> 16;
+                       command[2] = (addr & 0x0000FF00) >> 8;
+                       command[3] = 0;
+
+                       DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n",
+                               command[0], command[1], command[2], command[3]);
+
+                       status = spi_sync(spi, &msg);
+                       if (status < 0)
+                               DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n",
+                                       spi->dev.bus_id, addr, status);
+
+                       (void) dataflash_waitready(priv->spi);
+               }
+
+               /* (2) Program full page via Buffer1 */
+               addr += offset;
+               command[0] = OP_PROGRAM_VIA_BUF1;
+               command[1] = (addr & 0x00FF0000) >> 16;
+               command[2] = (addr & 0x0000FF00) >> 8;
+               command[3] = (addr & 0x000000FF);
+
+               DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n",
+                       command[0], command[1], command[2], command[3]);
+
+               x[1].tx_buf = writebuf;
+               x[1].len = writelen;
+               spi_message_add_tail(x + 1, &msg);
+               status = spi_sync(spi, &msg);
+               spi_transfer_del(x + 1);
+               if (status < 0)
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n",
+                               spi->dev.bus_id, addr, writelen, status);
+
+               (void) dataflash_waitready(priv->spi);
+
+
+#ifdef CONFIG_DATAFLASH_WRITE_VERIFY
+
+               /* (3) Compare to Buffer1 */
+               addr = pageaddr << priv->page_offset;
+               command[0] = OP_COMPARE_BUF1;
+               command[1] = (addr & 0x00FF0000) >> 16;
+               command[2] = (addr & 0x0000FF00) >> 8;
+               command[3] = 0;
+
+               DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n",
+                       command[0], command[1], command[2], command[3]);
+
+               status = spi_sync(spi, &msg);
+               if (status < 0)
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n",
+                               spi->dev.bus_id, addr, status);
+
+               status = dataflash_waitready(priv->spi);
+
+               /* Check result of the compare operation */
+               if ((status & (1 << 6)) == 1) {
+                       printk(KERN_ERR "%s: compare page %u, err %d\n",
+                               spi->dev.bus_id, pageaddr, status);
+                       remaining = 0;
+                       status = -EIO;
+                       break;
+               } else
+                       status = 0;
+
+#endif /* CONFIG_DATAFLASH_WRITE_VERIFY */
+
+               remaining = remaining - writelen;
+               pageaddr++;
+               offset = 0;
+               writebuf += writelen;
+               *retlen += writelen;
+
+               if (remaining > priv->page_size)
+                       writelen = priv->page_size;
+               else
+                       writelen = remaining;
+       }
+       up(&priv->lock);
+
+       return status;
+}
+
+/* ......................................................................... */
+
+/*
+ * Register DataFlash device with MTD subsystem.
+ */
+static int __devinit
+add_dataflash(struct spi_device *spi, char *name,
+               int nr_pages, int pagesize, int pageoffset)
+{
+       struct dataflash                *priv;
+       struct mtd_info                 *device;
+       struct flash_platform_data      *pdata = spi->dev.platform_data;
+
+       priv = (struct dataflash *) kzalloc(sizeof *priv, GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       init_MUTEX(&priv->lock);
+       priv->spi = spi;
+       priv->page_size = pagesize;
+       priv->page_offset = pageoffset;
+
+       /* name must be usable with cmdlinepart */
+       sprintf(priv->name, "spi%d.%d-%s",
+                       spi->master->bus_num, spi->chip_select,
+                       name);
+
+       device = &priv->mtd;
+       device->name = (pdata && pdata->name) ? pdata->name : priv->name;
+       device->size = nr_pages * pagesize;
+       device->erasesize = pagesize;
+       device->owner = THIS_MODULE;
+       device->type = MTD_DATAFLASH;
+       device->flags = MTD_CAP_NORFLASH;
+       device->erase = dataflash_erase;
+       device->read = dataflash_read;
+       device->write = dataflash_write;
+       device->priv = priv;
+
+       dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);
+       dev_set_drvdata(&spi->dev, priv);
+
+       if (mtd_has_partitions()) {
+               struct mtd_partition    *parts;
+               int                     nr_parts = 0;
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+               static const char *part_probes[] = { "cmdlinepart", NULL, };
+
+               nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);
+#endif
+
+               if (nr_parts <= 0 && pdata && pdata->parts) {
+                       parts = pdata->parts;
+                       nr_parts = pdata->nr_parts;
+               }
+
+               if (nr_parts > 0) {
+                       priv->partitioned = 1;
+                       return add_mtd_partitions(device, parts, nr_parts);
+               }
+       } else if (pdata && pdata->nr_parts)
+               dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
+                               pdata->nr_parts, device->name);
+
+       return add_mtd_device(device) == 1 ? -ENODEV : 0;
+}
+
+/*
+ * Detect and initialize DataFlash device:
+ *
+ *   Device      Density         ID code          #Pages PageSize  Offset
+ *   AT45DB011B  1Mbit   (128K)  xx0011xx (0x0c)    512    264      9
+ *   AT45DB021B  2Mbit   (256K)  xx0101xx (0x14)   1025    264      9
+ *   AT45DB041B  4Mbit   (512K)  xx0111xx (0x1c)   2048    264      9
+ *   AT45DB081B  8Mbit   (1M)    xx1001xx (0x24)   4096    264      9
+ *   AT45DB0161B 16Mbit  (2M)    xx1011xx (0x2c)   4096    528     10
+ *   AT45DB0321B 32Mbit  (4M)    xx1101xx (0x34)   8192    528     10
+ *   AT45DB0642  64Mbit  (8M)    xx111xxx (0x3c)   8192   1056     11
+ *   AT45DB1282  128Mbit (16M)   xx0100xx (0x10)  16384   1056     11
+ */
+static int __devinit dataflash_probe(struct spi_device *spi)
+{
+       int status;
+
+       status = dataflash_status(spi);
+       if (status <= 0 || status == 0xff) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n",
+                               spi->dev.bus_id, status);
+               if (status == 0xff)
+                       status = -ENODEV;
+               return status;
+       }
+
+       /* if there's a device there, assume it's dataflash.
+        * board setup should have set spi->max_speed_max to
+        * match f(car) for continuous reads, mode 0 or 3.
+        */
+       switch (status & 0x3c) {
+       case 0x0c:      /* 0 0 1 1 x x */
+               status = add_dataflash(spi, "AT45DB011B", 512, 264, 9);
+               break;
+       case 0x14:      /* 0 1 0 1 x x */
+               status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9);
+               break;
+       case 0x1c:      /* 0 1 1 1 x x */
+               status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9);
+               break;
+       case 0x24:      /* 1 0 0 1 x x */
+               status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9);
+               break;
+       case 0x2c:      /* 1 0 1 1 x x */
+               status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10);
+               break;
+       case 0x34:      /* 1 1 0 1 x x */
+               status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10);
+               break;
+       case 0x38:      /* 1 1 1 x x x */
+       case 0x3c:
+               status = add_dataflash(spi, "AT45DB642x", 8192, 1056, 11);
+               break;
+       /* obsolete AT45DB1282 not (yet?) supported */
+       default:
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n",
+                               spi->dev.bus_id, status & 0x3c);
+               status = -ENODEV;
+       }
+
+       if (status < 0)
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n",
+                               spi->dev.bus_id, status);
+
+       return status;
+}
+
+static int __devexit dataflash_remove(struct spi_device *spi)
+{
+       struct dataflash        *flash = dev_get_drvdata(&spi->dev);
+       int                     status;
+
+       DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id);
+
+       if (mtd_has_partitions() && flash->partitioned)
+               status = del_mtd_partitions(&flash->mtd);
+       else
+               status = del_mtd_device(&flash->mtd);
+       if (status == 0)
+               kfree(flash);
+       return status;
+}
+
+static struct spi_driver dataflash_driver = {
+       .driver = {
+               .name           = "mtd_dataflash",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+
+       .probe          = dataflash_probe,
+       .remove         = __devexit_p(dataflash_remove),
+
+       /* FIXME:  investigate suspend and resume... */
+};
+
+static int __init dataflash_init(void)
+{
+       return spi_register_driver(&dataflash_driver);
+}
+module_init(dataflash_init);
+
+static void __exit dataflash_exit(void)
+{
+       spi_unregister_driver(&dataflash_driver);
+}
+module_exit(dataflash_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrew Victor, David Brownell");
+MODULE_DESCRIPTION("MTD DataFlash driver");
index 21d4e8f4b7af4c9ffa2c0f851cec1136f2d5b94e..ec5e45e4e4efcfe9214e0076ed59c470cf2b90e7 100644 (file)
@@ -1506,7 +1506,7 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
        return 1;
 }
 
-static inline int __init doc_probe(unsigned long physadr)
+static int __init doc_probe(unsigned long physadr)
 {
        unsigned char ChipID;
        struct mtd_info *mtd;
index 5c15f3e9ea0723e4ce472bf0b55edd3af3849109..171999e67eecbafaf3da223df8736a4077b95c71 100644 (file)
@@ -1387,7 +1387,7 @@ config FORCEDETH
 
 config CS89x0
        tristate "CS89x0 support"
-       depends on NET_PCI && (ISA || ARCH_IXDP2X01 || ARCH_PNX010X)
+       depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X)
        ---help---
          Support for CS89x0 chipset based Ethernet cards. If you have a
          network (Ethernet) card of this type, say Y and read the
index e2cfde7e31eca8bf1736187909fbb4832286a66a..fab6586d87e9d79bce1b524d086fda2fabd445e2 100644 (file)
   Deepak Saxena     : dsaxena@plexity.net
                     : Intel IXDP2x01 (XScale ixp2x00 NPU) platform support
 
+  Dmitry Pervushin  : dpervushin@ru.mvista.com
+                    : PNX010X platform support
+
+  Deepak Saxena     : dsaxena@plexity.net
+                    : Intel IXDP2351 platform support
+
 */
 
 /* Always include 'config.h' first in case the user wants to turn on
@@ -171,6 +177,10 @@ static unsigned int cs8900_irq_map[] = {12,0,0,0};
 static unsigned int netcard_portlist[] __initdata =
    { 0x0300, 0};
 static unsigned int cs8900_irq_map[] = {1,0,0,0};
+#elif defined(CONFIG_MACH_IXDP2351)
+static unsigned int netcard_portlist[] __initdata = {IXDP2351_VIRT_CS8900_BASE, 0};
+static unsigned int cs8900_irq_map[] = {IRQ_IXDP2351_CS8900, 0, 0, 0};
+#include <asm/irq.h>
 #elif defined(CONFIG_ARCH_IXDP2X01)
 #include <asm/irq.h>
 static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
@@ -338,45 +348,55 @@ out:
 }
 #endif
 
-#if defined(CONFIG_ARCH_IXDP2X01)
-static int
+#if defined(CONFIG_MACH_IXDP2351)
+static u16
 readword(unsigned long base_addr, int portno)
 {
-       return (u16)__raw_readl(base_addr + (portno << 1));
+       return __raw_readw(base_addr + (portno << 1));
 }
 
 static void
-writeword(unsigned long base_addr, int portno, int value)
+writeword(unsigned long base_addr, int portno, u16 value)
 {
-       __raw_writel((u16)value, base_addr + (portno << 1));
+       __raw_writew(value, base_addr + (portno << 1));
 }
-#else
-#if defined(CONFIG_ARCH_PNX010X)
-static int
+#elif defined(CONFIG_ARCH_IXDP2X01)
+static u16
+readword(unsigned long base_addr, int portno)
+{
+       return __raw_readl(base_addr + (portno << 1));
+}
+
+static void
+writeword(unsigned long base_addr, int portno, u16 value)
+{
+       __raw_writel(value, base_addr + (portno << 1));
+}
+#elif defined(CONFIG_ARCH_PNX010X)
+static u16
 readword(unsigned long base_addr, int portno)
 {
        return inw(base_addr + (portno << 1));
 }
 
 static void
-writeword(unsigned long base_addr, int portno, int value)
+writeword(unsigned long base_addr, int portno, u16 value)
 {
        outw(value, base_addr + (portno << 1));
 }
 #else
-static int
+static u16
 readword(unsigned long base_addr, int portno)
 {
        return inw(base_addr + portno);
 }
 
 static void
-writeword(unsigned long base_addr, int portno, int value)
+writeword(unsigned long base_addr, int portno, u16 value)
 {
        outw(value, base_addr + portno);
 }
 #endif
-#endif
 
 static void
 readwords(unsigned long base_addr, int portno, void *buf, int length)
@@ -384,11 +404,11 @@ readwords(unsigned long base_addr, int portno, void *buf, int length)
        u8 *buf8 = (u8 *)buf;
 
        do {
-               u32 tmp32;
+               u16 tmp16;
 
-               tmp32 = readword(base_addr, portno);
-               *buf8++ = (u8)tmp32;
-               *buf8++ = (u8)(tmp32 >> 8);
+               tmp16 = readword(base_addr, portno);
+               *buf8++ = (u8)tmp16;
+               *buf8++ = (u8)(tmp16 >> 8);
        } while (--length);
 }
 
@@ -398,23 +418,23 @@ writewords(unsigned long base_addr, int portno, void *buf, int length)
        u8 *buf8 = (u8 *)buf;
 
        do {
-               u32 tmp32;
+               u16 tmp16;
 
-               tmp32 = *buf8++;
-               tmp32 |= (*buf8++) << 8;
-               writeword(base_addr, portno, tmp32);
+               tmp16 = *buf8++;
+               tmp16 |= (*buf8++) << 8;
+               writeword(base_addr, portno, tmp16);
        } while (--length);
 }
 
-static int
-readreg(struct net_device *dev, int regno)
+static u16
+readreg(struct net_device *dev, u16 regno)
 {
        writeword(dev->base_addr, ADD_PORT, regno);
        return readword(dev->base_addr, DATA_PORT);
 }
 
 static void
-writereg(struct net_device *dev, int regno, int value)
+writereg(struct net_device *dev, u16 regno, u16 value)
 {
        writeword(dev->base_addr, ADD_PORT, regno);
        writeword(dev->base_addr, DATA_PORT, value);
@@ -780,7 +800,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
        } else {
                i = lp->isa_config & INT_NO_MASK;
                if (lp->chip_type == CS8900) {
-#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
+#if defined(CONFIG_MACH_IXDP2351) || defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
                        i = cs8900_irq_map[0];
 #else
                        /* Translate the IRQ using the IRQ mapping table. */
@@ -1012,7 +1032,7 @@ skip_this_frame:
 
 void  __init reset_chip(struct net_device *dev)
 {
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
        struct net_local *lp = netdev_priv(dev);
        int ioaddr = dev->base_addr;
 #endif
@@ -1023,7 +1043,7 @@ void  __init reset_chip(struct net_device *dev)
        /* wait 30 ms */
        msleep(30);
 
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
        if (lp->chip_type != CS8900) {
                /* Hardware problem requires PNP registers to be reconfigured after a reset */
                writeword(ioaddr, ADD_PORT, PP_CS8920_ISAINT);
@@ -1287,7 +1307,7 @@ net_open(struct net_device *dev)
        else
 #endif
        {
-#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
+#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
                if (((1 << dev->irq) & lp->irq_map) == 0) {
                        printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
                                dev->name, dev->irq, lp->irq_map);
index 23de22631c644d8d40cb17b40295494666fe181d..4726722a063539a9736bf8305b8bb43603ca299e 100644 (file)
@@ -592,7 +592,7 @@ static inline void e100_write_flush(struct nic *nic)
        (void)readb(&nic->csr->scb.status);
 }
 
-static inline void e100_enable_irq(struct nic *nic)
+static void e100_enable_irq(struct nic *nic)
 {
        unsigned long flags;
 
@@ -602,7 +602,7 @@ static inline void e100_enable_irq(struct nic *nic)
        e100_write_flush(nic);
 }
 
-static inline void e100_disable_irq(struct nic *nic)
+static void e100_disable_irq(struct nic *nic)
 {
        unsigned long flags;
 
@@ -791,7 +791,7 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
 
 #define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
 #define E100_WAIT_SCB_FAST 20       /* delay like the old code */
-static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
+static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
 {
        unsigned long flags;
        unsigned int i;
@@ -822,7 +822,7 @@ err_unlock:
        return err;
 }
 
-static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
+static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
        void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
 {
        struct cb *cb;
@@ -1567,7 +1567,7 @@ static void e100_watchdog(unsigned long data)
        mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
 }
 
-static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb,
+static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
        struct sk_buff *skb)
 {
        cb->command = nic->tx_command;
@@ -1617,7 +1617,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        return 0;
 }
 
-static inline int e100_tx_clean(struct nic *nic)
+static int e100_tx_clean(struct nic *nic)
 {
        struct cb *cb;
        int tx_cleaned = 0;
@@ -1728,7 +1728,7 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
 }
 
 #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
-static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
+static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
 {
        if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
                return -ENOMEM;
@@ -1762,7 +1762,7 @@ static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
        return 0;
 }
 
-static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
+static int e100_rx_indicate(struct nic *nic, struct rx *rx,
        unsigned int *work_done, unsigned int work_to_do)
 {
        struct sk_buff *skb = rx->skb;
@@ -1822,7 +1822,7 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx,
        return 0;
 }
 
-static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done,
+static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
        unsigned int work_to_do)
 {
        struct rx *rx;
index d6388e1533f09778578a0eee49dad0d3dbed8af2..76139478c3df037dcf606131b873afdd41c24f2b 100644 (file)
@@ -94,7 +94,7 @@ static inline int card_wait_for_busy_clear(const int ioaddr[],
        const char* name);
 static inline int card_wait_for_ready(const int ioaddr[], const char* name,
        unsigned char in[]);
-static inline int card_send_command(const int ioaddr[], const char* name,
+static int card_send_command(const int ioaddr[], const char* name,
        const unsigned char out[], unsigned char in[]);
 
 /* SB1000 hardware routines to be used during frame rx interrupt */
@@ -309,7 +309,7 @@ card_wait_for_ready(const int ioaddr[], const char* name, unsigned char in[])
 }
 
 /* Card Send Command (cannot be used during an interrupt) */
-static inline int
+static int
 card_send_command(const int ioaddr[], const char* name,
        const unsigned char out[], unsigned char in[])
 {
index ffac50899454353b324d52a2593fbb281ab05d23..4b13b76425c1c0642c47c9ce77d3bd567fd425e2 100644 (file)
@@ -435,7 +435,7 @@ static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
 }
 
 
-static inline int
+static int
 hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
                     struct hostap_80211_rx_status *rx_stats, u16 type,
                     u16 stype)
@@ -499,7 +499,7 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
 
 
 /* Called only as a tasklet (software IRQ) */
-static inline struct net_device *prism2_rx_get_wds(local_info_t *local,
+static struct net_device *prism2_rx_get_wds(local_info_t *local,
                                                   u8 *addr)
 {
        struct hostap_interface *iface = NULL;
@@ -519,7 +519,7 @@ static inline struct net_device *prism2_rx_get_wds(local_info_t *local,
 }
 
 
-static inline int
+static int
 hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
                    u16 fc, struct net_device **wds)
 {
@@ -615,7 +615,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
 
 
 /* Called only as a tasklet (software IRQ) */
-static inline int
+static int
 hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
                        struct ieee80211_crypt_data *crypt)
 {
@@ -654,7 +654,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
 
 
 /* Called only as a tasklet (software IRQ) */
-static inline int
+static int
 hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
                             int keyidx, struct ieee80211_crypt_data *crypt)
 {
index abfae7fedebcfcc31a75b9631b8e6bcd993bd287..b1f142d9e232b39cc42f5195cf6fd7b8d11d84ca 100644 (file)
@@ -253,7 +253,7 @@ static void prism2_clear_cmd_queue(local_info_t *local)
  * @dev: pointer to net_device
  * @entry: Prism2 command queue entry to be issued
  */
-static inline int hfa384x_cmd_issue(struct net_device *dev,
+static int hfa384x_cmd_issue(struct net_device *dev,
                                    struct hostap_cmd_queue *entry)
 {
        struct hostap_interface *iface;
@@ -743,7 +743,7 @@ static void prism2_cmd_ev(struct net_device *dev)
 }
 
 
-static inline int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
+static int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
 {
        int tries = HFA384X_BAP_BUSY_TIMEOUT;
        int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
@@ -1904,7 +1904,7 @@ fail:
  * and will try to get the correct fid eventually. */
 #define EXTRA_FID_READ_TESTS
 
-static inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
+static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
 {
 #ifdef EXTRA_FID_READ_TESTS
        u16 val, val2, val3;
@@ -2581,7 +2581,7 @@ static void prism2_ev_tick(struct net_device *dev)
 
 
 /* Called only from hardware IRQ */
-static inline void prism2_check_magic(local_info_t *local)
+static void prism2_check_magic(local_info_t *local)
 {
        /* at least PCI Prism2.5 with bus mastering seems to sometimes
         * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the
index cf05661fb1bda768d037d5eb950ad9a283651ef7..7518384f34d964350796f41af2c0577272f4eac5 100644 (file)
@@ -411,7 +411,7 @@ static inline void write_nic_dword_auto_inc(struct net_device *dev, u32 val)
        write_register(dev, IPW_REG_AUTOINCREMENT_DATA, val);
 }
 
-static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
+static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
                                    const u8 * buf)
 {
        u32 aligned_addr;
@@ -449,7 +449,7 @@ static inline void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
                                    *buf);
 }
 
-static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
+static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
                                   u8 * buf)
 {
        u32 aligned_addr;
@@ -657,7 +657,7 @@ static void printk_buf(int level, const u8 * data, u32 len)
 
 #define MAX_RESET_BACKOFF 10
 
-static inline void schedule_reset(struct ipw2100_priv *priv)
+static void schedule_reset(struct ipw2100_priv *priv)
 {
        unsigned long now = get_seconds();
 
@@ -1130,7 +1130,7 @@ static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
        write_register(priv->net_dev, IPW_REG_GPIO, reg);
 }
 
-static inline int rf_kill_active(struct ipw2100_priv *priv)
+static int rf_kill_active(struct ipw2100_priv *priv)
 {
 #define MAX_RF_KILL_CHECKS 5
 #define RF_KILL_CHECK_DELAY 40
@@ -2177,7 +2177,7 @@ static const char *frame_types[] = {
 };
 #endif
 
-static inline int ipw2100_alloc_skb(struct ipw2100_priv *priv,
+static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
                                    struct ipw2100_rx_packet *packet)
 {
        packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
@@ -2201,7 +2201,7 @@ static inline int ipw2100_alloc_skb(struct ipw2100_priv *priv,
 #define SEARCH_SNAPSHOT 1
 
 #define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
-static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
+static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
 {
        int i;
        if (priv->snapshot[0])
@@ -2221,7 +2221,7 @@ static inline int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
        return 1;
 }
 
-static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv)
+static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
 {
        int i;
        if (!priv->snapshot[0])
@@ -2231,7 +2231,7 @@ static inline void ipw2100_snapshot_free(struct ipw2100_priv *priv)
        priv->snapshot[0] = NULL;
 }
 
-static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
+static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
                                    size_t len, int mode)
 {
        u32 i, j;
@@ -2288,7 +2288,7 @@ static inline u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
 static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
 #endif
 
-static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
+static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 {
 #ifdef CONFIG_IPW2100_DEBUG_C3
        struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2346,7 +2346,7 @@ static inline void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
        schedule_reset(priv);
 }
 
-static inline void isr_rx(struct ipw2100_priv *priv, int i,
+static void isr_rx(struct ipw2100_priv *priv, int i,
                          struct ieee80211_rx_stats *stats)
 {
        struct ipw2100_status *status = &priv->status_queue.drv[i];
@@ -2425,7 +2425,7 @@ static inline void isr_rx(struct ipw2100_priv *priv, int i,
        priv->rx_queue.drv[i].host_addr = packet->dma_addr;
 }
 
-static inline int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
+static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
 {
        struct ipw2100_status *status = &priv->status_queue.drv[i];
        struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
@@ -2481,7 +2481,7 @@ static inline int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
  * The WRITE index is cached in the variable 'priv->rx_queue.next'.
  *
  */
-static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
+static void __ipw2100_rx_process(struct ipw2100_priv *priv)
 {
        struct ipw2100_bd_queue *rxq = &priv->rx_queue;
        struct ipw2100_status_queue *sq = &priv->status_queue;
@@ -2634,7 +2634,7 @@ static inline void __ipw2100_rx_process(struct ipw2100_priv *priv)
  * for use by future command and data packets.
  *
  */
-static inline int __ipw2100_tx_process(struct ipw2100_priv *priv)
+static int __ipw2100_tx_process(struct ipw2100_priv *priv)
 {
        struct ipw2100_bd_queue *txq = &priv->tx_queue;
        struct ipw2100_bd *tbd;
index cdfe50207757392176a538f9276d13bffd730c31..819be2b6b7df03e87036217cf26d573cef4f3b43 100644 (file)
@@ -813,7 +813,7 @@ static void ipw_bg_led_link_off(void *data)
        up(&priv->sem);
 }
 
-static inline void __ipw_led_activity_on(struct ipw_priv *priv)
+static void __ipw_led_activity_on(struct ipw_priv *priv)
 {
        u32 led;
 
@@ -1508,7 +1508,7 @@ static ssize_t store_direct_dword(struct device *d,
 static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO,
                   show_direct_dword, store_direct_dword);
 
-static inline int rf_kill_active(struct ipw_priv *priv)
+static int rf_kill_active(struct ipw_priv *priv)
 {
        if (0 == (ipw_read32(priv, 0x30) & 0x10000))
                priv->status |= STATUS_RF_KILL_HW;
@@ -2359,7 +2359,7 @@ static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
 }
 
 /* perform a chip select operation */
-static inline void eeprom_cs(struct ipw_priv *priv)
+static void eeprom_cs(struct ipw_priv *priv)
 {
        eeprom_write_reg(priv, 0);
        eeprom_write_reg(priv, EEPROM_BIT_CS);
@@ -2368,7 +2368,7 @@ static inline void eeprom_cs(struct ipw_priv *priv)
 }
 
 /* perform a chip select operation */
-static inline void eeprom_disable_cs(struct ipw_priv *priv)
+static void eeprom_disable_cs(struct ipw_priv *priv)
 {
        eeprom_write_reg(priv, EEPROM_BIT_CS);
        eeprom_write_reg(priv, 0);
@@ -2475,7 +2475,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv)
        IPW_DEBUG_TRACE("<<\n");
 }
 
-static inline void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
+static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
 {
        count >>= 2;
        if (!count)
@@ -2772,7 +2772,7 @@ static inline int ipw_alive(struct ipw_priv *priv)
        return ipw_read32(priv, 0x90) == 0xd55555d5;
 }
 
-static inline int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
+static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
                               int timeout)
 {
        int i = 0;
@@ -3150,7 +3150,7 @@ static int ipw_get_fw(struct ipw_priv *priv,
 
 #define IPW_RX_BUF_SIZE (3000)
 
-static inline void ipw_rx_queue_reset(struct ipw_priv *priv,
+static void ipw_rx_queue_reset(struct ipw_priv *priv,
                                      struct ipw_rx_queue *rxq)
 {
        unsigned long flags;
@@ -3608,7 +3608,7 @@ static void ipw_tx_queue_free(struct ipw_priv *priv)
        ipw_queue_tx_free(priv, &priv->txq[3]);
 }
 
-static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
+static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
 {
        /* First 3 bytes are manufacturer */
        bssid[0] = priv->mac_addr[0];
@@ -3622,7 +3622,7 @@ static inline void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
        bssid[0] |= 0x02;       /* set local assignment bit (IEEE802) */
 }
 
-static inline u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
+static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
 {
        struct ipw_station_entry entry;
        int i;
@@ -3655,7 +3655,7 @@ static inline u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
        return i;
 }
 
-static inline u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
+static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
 {
        int i;
 
@@ -3794,7 +3794,7 @@ static void inline average_init(struct average *avg)
        memset(avg, 0, sizeof(*avg));
 }
 
-static void inline average_add(struct average *avg, s16 val)
+static void average_add(struct average *avg, s16 val)
 {
        avg->sum -= avg->entries[avg->pos];
        avg->sum += val;
@@ -3805,7 +3805,7 @@ static void inline average_add(struct average *avg, s16 val)
        }
 }
 
-static s16 inline average_value(struct average *avg)
+static s16 average_value(struct average *avg)
 {
        if (!unlikely(avg->init)) {
                if (avg->pos)
@@ -3847,7 +3847,7 @@ static void ipw_reset_stats(struct ipw_priv *priv)
 
 }
 
-static inline u32 ipw_get_max_rate(struct ipw_priv *priv)
+static u32 ipw_get_max_rate(struct ipw_priv *priv)
 {
        u32 i = 0x80000000;
        u32 mask = priv->rates_mask;
@@ -4087,7 +4087,7 @@ static void ipw_bg_gather_stats(void *data)
  * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
  * Above disassociate threshold, give up and stop scanning.
  * Roaming is disabled if disassociate_threshold <= roaming_threshold  */
-static inline void ipw_handle_missed_beacon(struct ipw_priv *priv,
+static void ipw_handle_missed_beacon(struct ipw_priv *priv,
                                            int missed_count)
 {
        priv->notif_missed_beacons = missed_count;
@@ -4157,7 +4157,7 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv,
  * Handle host notification packet.
  * Called from interrupt routine
  */
-static inline void ipw_rx_notification(struct ipw_priv *priv,
+static void ipw_rx_notification(struct ipw_priv *priv,
                                       struct ipw_rx_notification *notif)
 {
        notif->size = le16_to_cpu(notif->size);
@@ -5095,7 +5095,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv,
        return 1;
 }
 
-static inline void ipw_copy_rates(struct ipw_supported_rates *dest,
+static void ipw_copy_rates(struct ipw_supported_rates *dest,
                                  const struct ipw_supported_rates *src)
 {
        u8 i;
@@ -5856,7 +5856,7 @@ static void ipw_debug_config(struct ipw_priv *priv)
 #define ipw_debug_config(x) do {} while (0)
 #endif
 
-static inline void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
+static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
 {
        /* TODO: Verify that this works... */
        struct ipw_fixed_rate fr = {
@@ -7634,7 +7634,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
 }
 #endif
 
-static inline int is_network_packet(struct ipw_priv *priv,
+static int is_network_packet(struct ipw_priv *priv,
                                    struct ieee80211_hdr_4addr *header)
 {
        /* Filter incoming packets to determine if they are targetted toward
@@ -7672,7 +7672,7 @@ static inline int is_network_packet(struct ipw_priv *priv,
 
 #define IPW_PACKET_RETRY_TIME HZ
 
-static inline int is_duplicate_packet(struct ipw_priv *priv,
+static  int is_duplicate_packet(struct ipw_priv *priv,
                                      struct ieee80211_hdr_4addr *header)
 {
        u16 sc = le16_to_cpu(header->seq_ctl);
@@ -9581,7 +9581,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
 
 /* net device stuff */
 
-static inline void init_sys_config(struct ipw_sys_config *sys_config)
+static  void init_sys_config(struct ipw_sys_config *sys_config)
 {
        memset(sys_config, 0, sizeof(struct ipw_sys_config));
        sys_config->bt_coexistence = 1; /* We may need to look into prvStaBtConfig */
@@ -9627,7 +9627,7 @@ modify to send one tfd per fragment instead of using chunking.  otherwise
 we need to heavily modify the ieee80211_skb_to_txb.
 */
 
-static inline int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
+static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
                             int pri)
 {
        struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)
index b0d8b5b03152769974b382809418b47d1bd6fb08..ff192e96268a1c69519a3c35aac6386bec35ed10 100644 (file)
@@ -102,7 +102,7 @@ static inline void hacr_write(unsigned long ioaddr, u16 hacr)
  * Write to card's Host Adapter Command Register. Include a delay for
  * those times when it is needed.
  */
-static inline void hacr_write_slow(unsigned long ioaddr, u16 hacr)
+static void hacr_write_slow(unsigned long ioaddr, u16 hacr)
 {
        hacr_write(ioaddr, hacr);
        /* delay might only be needed sometimes */
@@ -242,7 +242,7 @@ static void psa_write(unsigned long ioaddr, u16 hacr, int o,        /* Offset in PSA */
  * The Windows drivers don't use the CRC, but the AP and the PtP tool
  * depend on it.
  */
-static inline u16 psa_crc(u8 * psa,    /* The PSA */
+static u16 psa_crc(u8 * psa,   /* The PSA */
                              int size)
 {                              /* Number of short for CRC */
        int byte_cnt;           /* Loop on the PSA */
@@ -310,7 +310,7 @@ static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u
 /*
  * Write 1 byte to the MMC.
  */
-static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
+static void mmc_out(unsigned long ioaddr, u16 o, u8 d)
 {
        int count = 0;
 
@@ -326,7 +326,7 @@ static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
  * Routine to write bytes to the Modem Management Controller.
  * We start at the end because it is the way it should be!
  */
-static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
+static void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
 {
        o += n;
        b += n;
@@ -340,7 +340,7 @@ static inline void mmc_write(unsigned long ioaddr, u8 o, u8 * b, int n)
  * Read a byte from the MMC.
  * Optimised version for 1 byte, avoid using memory.
  */
-static inline u8 mmc_in(unsigned long ioaddr, u16 o)
+static u8 mmc_in(unsigned long ioaddr, u16 o)
 {
        int count = 0;
 
@@ -587,7 +587,7 @@ static void wv_ack(struct net_device * dev)
  * Set channel attention bit and busy wait until command has
  * completed, then acknowledge completion of the command.
  */
-static inline int wv_synchronous_cmd(struct net_device * dev, const char *str)
+static int wv_synchronous_cmd(struct net_device * dev, const char *str)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long ioaddr = dev->base_addr;
@@ -633,7 +633,7 @@ static inline int wv_synchronous_cmd(struct net_device * dev, const char *str)
  * Configuration commands completion interrupt.
  * Check if done, and if OK.
  */
-static inline int
+static int
 wv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp)
 {
        unsigned short mcs_addr;
@@ -843,7 +843,7 @@ if (lp->tx_n_in_use > 0)
  * wavelan_interrupt is not an option), so you may experience
  * delays sometimes.
  */
-static inline void wv_82586_reconfig(struct net_device * dev)
+static void wv_82586_reconfig(struct net_device * dev)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long flags;
@@ -1281,7 +1281,7 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */
  * This is the information which is displayed by the driver at startup.
  * There are lots of flags for configuring it to your liking.
  */
-static inline void wv_init_info(struct net_device * dev)
+static void wv_init_info(struct net_device * dev)
 {
        short ioaddr = dev->base_addr;
        net_local *lp = (net_local *) dev->priv;
@@ -1502,7 +1502,7 @@ static int wavelan_set_mac_address(struct net_device * dev, void *addr)
  * It's a bit complicated and you don't really want to look into it.
  * (called in wavelan_ioctl)
  */
-static inline int wv_set_frequency(unsigned long ioaddr,       /* I/O port of the card */
+static int wv_set_frequency(unsigned long ioaddr,      /* I/O port of the card */
                                   iw_freq * frequency)
 {
        const int BAND_NUM = 10;        /* Number of bands */
@@ -1677,7 +1677,7 @@ static inline int wv_set_frequency(unsigned long ioaddr,  /* I/O port of the card
 /*
  * Give the list of available frequencies.
  */
-static inline int wv_frequency_list(unsigned long ioaddr,      /* I/O port of the card */
+static int wv_frequency_list(unsigned long ioaddr,     /* I/O port of the card */
                                    iw_freq * list,     /* List of frequencies to fill */
                                    int max)
 {                              /* Maximum number of frequencies */
@@ -2489,7 +2489,7 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev)
  * Note: if any errors occur, the packet is "dropped on the floor".
  * (called by wv_packet_rcv())
  */
-static inline void
+static void
 wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
 {
        net_local *lp = (net_local *) dev->priv;
@@ -2585,7 +2585,7 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize)
  * (called in wavelan_interrupt()).
  * Note : the spinlock is already grabbed for us.
  */
-static inline void wv_receive(struct net_device * dev)
+static void wv_receive(struct net_device * dev)
 {
        unsigned long ioaddr = dev->base_addr;
        net_local *lp = (net_local *) dev->priv;
@@ -2768,7 +2768,7 @@ static inline void wv_receive(struct net_device * dev)
  *
  * (called in wavelan_packet_xmit())
  */
-static inline int wv_packet_write(struct net_device * dev, void *buf, short length)
+static int wv_packet_write(struct net_device * dev, void *buf, short length)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long ioaddr = dev->base_addr;
@@ -2964,7 +2964,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
  * Routine to initialize the Modem Management Controller.
  * (called by wv_hw_reset())
  */
-static inline int wv_mmc_init(struct net_device * dev)
+static int wv_mmc_init(struct net_device * dev)
 {
        unsigned long ioaddr = dev->base_addr;
        net_local *lp = (net_local *) dev->priv;
@@ -3136,7 +3136,7 @@ static inline int wv_mmc_init(struct net_device * dev)
  * Start the receive unit.
  * (called by wv_hw_reset())
  */
-static inline int wv_ru_start(struct net_device * dev)
+static int wv_ru_start(struct net_device * dev)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long ioaddr = dev->base_addr;
@@ -3228,7 +3228,7 @@ static inline int wv_ru_start(struct net_device * dev)
  *
  * (called by wv_hw_reset())
  */
-static inline int wv_cu_start(struct net_device * dev)
+static int wv_cu_start(struct net_device * dev)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long ioaddr = dev->base_addr;
@@ -3329,7 +3329,7 @@ static inline int wv_cu_start(struct net_device * dev)
  *
  * (called by wv_hw_reset())
  */
-static inline int wv_82586_start(struct net_device * dev)
+static int wv_82586_start(struct net_device * dev)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long ioaddr = dev->base_addr;
@@ -3641,7 +3641,7 @@ static void wv_82586_config(struct net_device * dev)
  * WaveLAN controller (i82586).
  * (called by wavelan_close())
  */
-static inline void wv_82586_stop(struct net_device * dev)
+static void wv_82586_stop(struct net_device * dev)
 {
        net_local *lp = (net_local *) dev->priv;
        unsigned long ioaddr = dev->base_addr;
index 7146b69b812cff19ad6ff2f8bd80acea4a971a91..0aa14c92b5700eca800e937de7ed17e2024e83b2 100644 (file)
@@ -380,8 +380,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &pci_bus_type;
-       drv->driver.probe = pci_device_probe;
-       drv->driver.remove = pci_device_remove;
        /* FIXME, once all of the existing PCI drivers have been fixed to set
         * the pci shutdown function, this test can go away. */
        if (!drv->driver.shutdown)
@@ -513,6 +511,8 @@ struct bus_type pci_bus_type = {
        .name           = "pci",
        .match          = pci_bus_match,
        .uevent         = pci_uevent,
+       .probe          = pci_device_probe,
+       .remove         = pci_device_remove,
        .suspend        = pci_device_suspend,
        .resume         = pci_device_resume,
        .dev_attrs      = pci_dev_attrs,
index 621ec459d27a10639b48cb5cb5c26d7ea7320f8f..0a424a4e8187f8c3a80509014acbbb86399af7d0 100644 (file)
@@ -311,8 +311,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
        /* initialize common fields */
        driver->drv.bus = &pcmcia_bus_type;
        driver->drv.owner = driver->owner;
-       driver->drv.probe = pcmcia_device_probe;
-       driver->drv.remove = pcmcia_device_remove;
 
        return driver_register(&driver->drv);
 }
@@ -1200,6 +1198,8 @@ struct bus_type pcmcia_bus_type = {
        .uevent = pcmcia_bus_uevent,
        .match = pcmcia_bus_match,
        .dev_attrs = pcmcia_dev_attrs,
+       .probe = pcmcia_device_probe,
+       .remove = pcmcia_device_remove,
        .suspend = pcmcia_dev_suspend,
        .resume = pcmcia_dev_resume,
 };
index 15fb758a9e526e0428fe88fe1ceb8e03d067906f..7cafacdd12b0a4dae9fea941b3b8efc0076fea85 100644 (file)
@@ -195,6 +195,8 @@ static int pnp_bus_resume(struct device *dev)
 struct bus_type pnp_bus_type = {
        .name   = "pnp",
        .match  = pnp_bus_match,
+       .probe  = pnp_device_probe,
+       .remove = pnp_device_remove,
        .suspend = pnp_bus_suspend,
        .resume = pnp_bus_resume,
 };
@@ -215,8 +217,6 @@ int pnp_register_driver(struct pnp_driver *drv)
 
        drv->driver.name = drv->name;
        drv->driver.bus = &pnp_bus_type;
-       drv->driver.probe = pnp_device_probe;
-       drv->driver.remove = pnp_device_remove;
 
        count = driver_register(&drv->driver);
 
index dc749609699aa178e5e1321942d44930378d2285..5480119ff9d36d94af3dce527dbaacac4d5811d7 100644 (file)
@@ -147,8 +147,6 @@ int rio_register_driver(struct rio_driver *rdrv)
        /* initialize common driver fields */
        rdrv->driver.name = rdrv->name;
        rdrv->driver.bus = &rio_bus_type;
-       rdrv->driver.probe = rio_device_probe;
-       rdrv->driver.remove = rio_device_remove;
 
        /* register with core */
        return driver_register(&rdrv->driver);
@@ -204,7 +202,9 @@ static struct device rio_bus = {
 struct bus_type rio_bus_type = {
        .name = "rapidio",
        .match = rio_match_bus,
-       .dev_attrs = rio_dev_attrs
+       .dev_attrs = rio_dev_attrs,
+       .probe = rio_device_probe,
+       .remove = rio_device_remove,
 };
 
 /**
index 9c25654b1e75f5da0eabebc7c6f203b4e49691a8..ef4c687e7c01164af3e9ecc7417dcb8cb90d63b6 100644 (file)
@@ -1635,7 +1635,7 @@ dasd_setup_queue(struct dasd_device * device)
        blk_queue_max_hw_segments(device->request_queue, -1L);
        blk_queue_max_segment_size(device->request_queue, -1L);
        blk_queue_segment_boundary(device->request_queue, -1L);
-       blk_queue_ordered(device->request_queue, 1);
+       blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);
 }
 
 /*
index 83e6a060668ead9e75fb718153fd8ee14c0229d5..cd2cc28e16a70181780ac3cc2d425f4422ddb035 100644 (file)
@@ -2,12 +2,12 @@
  *  drivers/s390/cio/airq.c
  *   S/390 common I/O routines -- support for adapter interruptions
  *
- *   $Revision: 1.12 $
+ *   $Revision: 1.15 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
  */
 
index daf21e03b21d43b5e632713f03e0bb9794624558..72f27c151c09fba2c78b5e6b3f1dfb0ef9484f4b 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/blacklist.c
  *   S/390 common I/O routines -- blacklisting of specific devices
- *   $Revision: 1.39 $
+ *   $Revision: 1.42 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
  */
 
index e849289d4f3c708a2029794c9f01f9349213e561..6c077ad71edc41e5c16e24ae270107a4bb490828 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
- *   $Revision: 1.33 $
+ *   $Revision: 1.35 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                       IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *               Cornelia Huck (cohuck@de.ibm.com)
+ *               Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -52,11 +52,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
        return 0;
 }
 
-static struct bus_type ccwgroup_bus_type = {
-       .name    = "ccwgroup",
-       .match   = ccwgroup_bus_match,
-       .uevent = ccwgroup_uevent,
-};
+static struct bus_type ccwgroup_bus_type;
 
 static inline void
 __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
@@ -389,6 +385,14 @@ ccwgroup_remove (struct device *dev)
        return 0;
 }
 
+static struct bus_type ccwgroup_bus_type = {
+       .name   = "ccwgroup",
+       .match  = ccwgroup_bus_match,
+       .uevent = ccwgroup_uevent,
+       .probe  = ccwgroup_probe,
+       .remove = ccwgroup_remove,
+};
+
 int
 ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
 {
@@ -396,8 +400,6 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
        cdriver->driver = (struct device_driver) {
                .bus = &ccwgroup_bus_type,
                .name = cdriver->name,
-               .probe = ccwgroup_probe,
-               .remove = ccwgroup_remove,
        };
 
        return driver_register(&cdriver->driver);
index 7270808c02d140a99973319cc67fa03522082689..2cbb724791a822bf34d3bea4cc4806140f7b5dcd 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/chsc.c
  *   S/390 common I/O routines -- channel subsystem call
- *   $Revision: 1.126 $
+ *   $Revision: 1.128 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
  */
 
index 7376bc87206da4b46af909c5af41edc468e3c7f7..6223b06d27d5d767a86333451b3e11ef1d23d80c 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/cio.c
  *   S/390 common I/O routines -- low level i/o calls
- *   $Revision: 1.138 $
+ *   $Revision: 1.140 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *                           IBM Corporation
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Arnd Bergmann (arndb@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
index e565193650c767038b8046a9309e38b5734bc86f..516108779f6038b9e4c4ca2f9e68997b345ceba8 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/css.c
  *  driver for channel subsystem
- *   $Revision: 1.93 $
+ *   $Revision: 1.96 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -542,9 +542,41 @@ css_bus_match (struct device *dev, struct device_driver *drv)
        return 0;
 }
 
+static int
+css_probe (struct device *dev)
+{
+       struct subchannel *sch;
+
+       sch = to_subchannel(dev);
+       sch->driver = container_of (dev->driver, struct css_driver, drv);
+       return (sch->driver->probe ? sch->driver->probe(sch) : 0);
+}
+
+static int
+css_remove (struct device *dev)
+{
+       struct subchannel *sch;
+
+       sch = to_subchannel(dev);
+       return (sch->driver->remove ? sch->driver->remove(sch) : 0);
+}
+
+static void
+css_shutdown (struct device *dev)
+{
+       struct subchannel *sch;
+
+       sch = to_subchannel(dev);
+       if (sch->driver->shutdown)
+               sch->driver->shutdown(sch);
+}
+
 struct bus_type css_bus_type = {
-       .name  = "css",
-       .match = &css_bus_match,
+       .name     = "css",
+       .match    = css_bus_match,
+       .probe    = css_probe,
+       .remove   = css_remove,
+       .shutdown = css_shutdown,
 };
 
 subsys_initcall(init_channel_subsystem);
index 251ebd7a7d3a260ce07ad9c77cd13cc28bd57cbc..b6375861cb3766188d85240e823828abca0e526c 100644 (file)
@@ -115,6 +115,7 @@ struct ccw_device_private {
  * Currently, we only care about I/O subchannels (type 0), these
  * have a ccw_device connected to them.
  */
+struct subchannel;
 struct css_driver {
        unsigned int subchannel_type;
        struct device_driver drv;
@@ -122,6 +123,9 @@ struct css_driver {
        int (*notify)(struct device *, int);
        void (*verify)(struct device *);
        void (*termination)(struct device *);
+       int (*probe)(struct subchannel *);
+       int (*remove)(struct subchannel *);
+       void (*shutdown)(struct subchannel *);
 };
 
 /*
@@ -143,7 +147,7 @@ extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
 struct channel_subsystem {
        u8 cssid;
        int valid;
-       struct channel_path *chps[__MAX_CHPID];
+       struct channel_path *chps[__MAX_CHPID + 1];
        struct device device;
        struct pgid global_pgid;
 };
index fa3e4c0a25364d2427800a7a986c621d92a39866..a67e7e60e33009b27f7812003195dbccb93737b2 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.137 $
+ *   $Revision: 1.140 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
  *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *              Cornelia Huck (cohuck@de.ibm.com)
+ *              Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 #include <linux/config.h>
@@ -107,33 +107,29 @@ ccw_uevent (struct device *dev, char **envp, int num_envp,
        return 0;
 }
 
-struct bus_type ccw_bus_type = {
-       .name  = "ccw",
-       .match = &ccw_bus_match,
-       .uevent = &ccw_uevent,
-};
+struct bus_type ccw_bus_type;
 
-static int io_subchannel_probe (struct device *);
-static int io_subchannel_remove (struct device *);
+static int io_subchannel_probe (struct subchannel *);
+static int io_subchannel_remove (struct subchannel *);
 void io_subchannel_irq (struct device *);
 static int io_subchannel_notify(struct device *, int);
 static void io_subchannel_verify(struct device *);
 static void io_subchannel_ioterm(struct device *);
-static void io_subchannel_shutdown(struct device *);
+static void io_subchannel_shutdown(struct subchannel *);
 
 struct css_driver io_subchannel_driver = {
        .subchannel_type = SUBCHANNEL_TYPE_IO,
        .drv = {
                .name = "io_subchannel",
                .bus  = &css_bus_type,
-               .probe = &io_subchannel_probe,
-               .remove = &io_subchannel_remove,
-               .shutdown = &io_subchannel_shutdown,
        },
        .irq = io_subchannel_irq,
        .notify = io_subchannel_notify,
        .verify = io_subchannel_verify,
        .termination = io_subchannel_ioterm,
+       .probe = io_subchannel_probe,
+       .remove = io_subchannel_remove,
+       .shutdown = io_subchannel_shutdown,
 };
 
 struct workqueue_struct *ccw_device_work;
@@ -803,14 +799,12 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
 }
 
 static int
-io_subchannel_probe (struct device *pdev)
+io_subchannel_probe (struct subchannel *sch)
 {
-       struct subchannel *sch;
        struct ccw_device *cdev;
        int rc;
        unsigned long flags;
 
-       sch = to_subchannel(pdev);
        if (sch->dev.driver_data) {
                /*
                 * This subchannel already has an associated ccw_device.
@@ -846,7 +840,7 @@ io_subchannel_probe (struct device *pdev)
        memset(cdev->private, 0, sizeof(struct ccw_device_private));
        atomic_set(&cdev->private->onoff, 0);
        cdev->dev = (struct device) {
-               .parent = pdev,
+               .parent = &sch->dev,
                .release = ccw_device_release,
        };
        INIT_LIST_HEAD(&cdev->private->kick_work.entry);
@@ -859,7 +853,7 @@ io_subchannel_probe (struct device *pdev)
                return -ENODEV;
        }
 
-       rc = io_subchannel_recog(cdev, to_subchannel(pdev));
+       rc = io_subchannel_recog(cdev, sch);
        if (rc) {
                spin_lock_irqsave(&sch->lock, flags);
                sch->dev.driver_data = NULL;
@@ -883,17 +877,17 @@ ccw_device_unregister(void *data)
 }
 
 static int
-io_subchannel_remove (struct device *dev)
+io_subchannel_remove (struct subchannel *sch)
 {
        struct ccw_device *cdev;
        unsigned long flags;
 
-       if (!dev->driver_data)
+       if (!sch->dev.driver_data)
                return 0;
-       cdev = dev->driver_data;
+       cdev = sch->dev.driver_data;
        /* Set ccw device to not operational and drop reference. */
        spin_lock_irqsave(cdev->ccwlock, flags);
-       dev->driver_data = NULL;
+       sch->dev.driver_data = NULL;
        cdev->private->state = DEV_STATE_NOT_OPER;
        spin_unlock_irqrestore(cdev->ccwlock, flags);
        /*
@@ -948,14 +942,12 @@ io_subchannel_ioterm(struct device *dev)
 }
 
 static void
-io_subchannel_shutdown(struct device *dev)
+io_subchannel_shutdown(struct subchannel *sch)
 {
-       struct subchannel *sch;
        struct ccw_device *cdev;
        int ret;
 
-       sch = to_subchannel(dev);
-       cdev = dev->driver_data;
+       cdev = sch->dev.driver_data;
 
        if (cio_is_console(sch->schid))
                return;
@@ -1129,6 +1121,14 @@ ccw_device_remove (struct device *dev)
        return 0;
 }
 
+struct bus_type ccw_bus_type = {
+       .name   = "ccw",
+       .match  = ccw_bus_match,
+       .uevent = ccw_uevent,
+       .probe  = ccw_device_probe,
+       .remove = ccw_device_remove,
+};
+
 int
 ccw_driver_register (struct ccw_driver *cdriver)
 {
@@ -1136,8 +1136,6 @@ ccw_driver_register (struct ccw_driver *cdriver)
 
        drv->bus = &ccw_bus_type;
        drv->name = cdriver->name;
-       drv->probe = ccw_device_probe;
-       drv->remove = ccw_device_remove;
 
        return driver_register(drv);
 }
index 23d12b65e5fa2bc8ab00fb0c65320d43047e422e..b302779e7cffcb9ec10f5aa580b1c171fafee2a7 100644 (file)
@@ -4,7 +4,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
index 04ceba343db8ef66209c54d0467d4473a27e4d8e..e60b2d8103b8b547627405b755f4b193ac6055c0 100644 (file)
@@ -3,7 +3,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * Sense ID functions.
index 143b6c25a4e6b228c408636b3a67e1cfa3d5467a..8b0218949b6287eb9b4480821e0d197a6c82414c 100644 (file)
@@ -1,12 +1,12 @@
 /*
  *  drivers/s390/cio/device_ops.c
  *
- *   $Revision: 1.58 $
+ *   $Revision: 1.61 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- *               Cornelia Huck (cohuck@de.ibm.com)
+ *               Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/config.h>
 #include <linux/module.h>
index 052832d03d3873ca41034f3dcf9a4c39be1caa4c..d2a5b04d7cbab266e7d2e540b9d3968cfe10502b 100644 (file)
@@ -3,7 +3,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * Path Group ID functions.
index db09c209098b306ac3c3e038da5ab7d1970c4f43..dad4dd9887c9eaa4e64f4bc923be24839a114a1f 100644 (file)
@@ -3,7 +3,7 @@
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
- *    Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * Status accumulation and basic sense functions.
index 30a836ffc31fc51fe4b95513c093bee1ec5f78ee..77be2c39bfe40df778ec6c021ba7bcf37b9170f9 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright 2000,2002 IBM Corporation
  * Author(s):             Utz Bacher <utz.bacher@de.ibm.com>
- * 2.6 cio integration by Cornelia Huck <cohuck@de.ibm.com>
+ * 2.6 cio integration by Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  * Restriction: only 63 iqdio subchannels would have its own indicator,
  * after that, subsequent subchannels share one indicator
@@ -56,7 +56,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.114 $"
+#define VERSION_QDIO_C "$Revision: 1.117 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
index 0db4f57a6a95e4a60538031bcdd09b9ae7a51eb8..1901feef07d9a83d7df43447c5c32ee13924cf04 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.78 2005/09/07 12:18:02 pavlic Exp $
+ * $Id: ctcmain.c,v 1.79 2006/01/11 11:32:18 cohuck Exp $
  *
  * CTC / ESCON network driver
  *
@@ -8,7 +8,7 @@
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
  *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
              Peter Tiedemann (ptiedem@de.ibm.com)
- * Driver Model stuff by : Cornelia Huck <cohuck@de.ibm.com>
+ * Driver Model stuff by : Cornelia Huck <huckc@de.ibm.com>
  *
  * Documentation used:
  *  - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -37,7 +37,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.78 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.79 $
  *
  */
 #undef DEBUG
@@ -248,7 +248,7 @@ static void
 print_banner(void)
 {
        static int printed = 0;
-       char vbuf[] = "$Revision: 1.78 $";
+       char vbuf[] = "$Revision: 1.79 $";
        char *version = vbuf;
 
        if (printed)
index 77dacb46573223232125700dd3f8d92365c1ec79..2014fb7a4881f131052c79716e37f920dca4e156 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * $Id: cu3088.c,v 1.36 2005/10/25 14:37:17 cohuck Exp $
+ * $Id: cu3088.c,v 1.38 2006/01/12 14:33:09 cohuck Exp $
  *
  * CTC / LCS ccw_device driver
  *
  * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Arnd Bergmann <arndb@de.ibm.com>
- *            Cornelia Huck <cohuck@de.ibm.com>
+ *            Cornelia Huck <cornelia.huck@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
index 69425a7a6e98a5b71f4fbb6df2826ad61c1bb2a7..ac4c4b83fe1701f297329c03e1ef9f2f1a7a752d 100644 (file)
@@ -1,12 +1,13 @@
 /*
- * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $
+ * $Id: netiucv.c,v 1.69 2006/01/12 14:33:09 cohuck Exp $
  *
  * IUCV network driver
  *
  * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
  * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  *
- * Driverfs integration and all bugs therein by Cornelia Huck(cohuck@de.ibm.com)
+ * Sysfs integration and all bugs therein by Cornelia Huck
+ * (cornelia.huck@de.ibm.com)
  *
  * Documentation used:
  *  the source of the original IUCV driver by:
@@ -30,7 +31,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.66 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.69 $
  *
  */
 \f
@@ -2076,7 +2077,7 @@ DRIVER_ATTR(remove, 0200, NULL, remove_write);
 static void
 netiucv_banner(void)
 {
-       char vbuf[] = "$Revision: 1.66 $";
+       char vbuf[] = "$Revision: 1.69 $";
        char *version = vbuf;
 
        if ((version = strchr(version, ':'))) {
index 566cc3d185b628c4609850dc4d82b8ad9e1ca527..206518c7d3322dba7d723ada73df1d3b48dca6f8 100644 (file)
@@ -1,11 +1,11 @@
 /*
  *  drivers/s390/s390_rdev.c
  *  s390 root device
- *   $Revision: 1.2 $
+ *   $Revision: 1.4 $
  *
  *    Copyright (C) 2002, 2005 IBM Deutschland Entwicklung GmbH,
  *                      IBM Corporation
- *    Author(s): Cornelia Huck (cohuck@de.ibm.com)
+ *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
  *               Carsten Otte  (cotte@de.ibm.com)
  */
 
index 5e84c5aa777977fac96b7b86d42be9547b70f779..167fef39d8a789400d0a41968e23d64f7972ef79 100644 (file)
@@ -1125,6 +1125,8 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
        zfcp_free_low_mem_buffers(adapter);
        /* free memory of adapter data structure and queues */
        zfcp_qdio_free_queues(adapter);
+       kfree(adapter->fc_stats);
+       kfree(adapter->stats_reset_data);
        ZFCP_LOG_TRACE("freeing adapter structure\n");
        kfree(adapter);
  out:
index d81b737d68ccafa8c92b3afe7738e7587ecfd596..9bb511083a261a4a40c9506a26d0f26a8a1d559a 100644 (file)
@@ -921,7 +921,6 @@ struct zfcp_adapter {
        u32                     physical_s_id;     /* local FC port ID */
        struct ccw_device       *ccw_device;       /* S/390 ccw device */
        u8                      fc_service_class;
-       u32                     fc_topology;       /* FC topology */
        u32                     hydra_version;     /* Hydra version */
        u32                     fsf_lic_version;
        u32                     adapter_features;  /* FCP channel features */
@@ -978,6 +977,9 @@ struct zfcp_adapter {
        struct zfcp_adapter_mempool     pool;      /* Adapter memory pools */
        struct qdio_initialize  qdio_init_data;    /* for qdio_establish */
        struct device           generic_services;  /* directory for WKA ports */
+       struct fc_host_statistics *fc_stats;
+       struct fsf_qtcb_bottom_port *stats_reset_data;
+       unsigned long           stats_reset;
 };
 
 /*
index ee7314d8c2da8bed70dbb84345ca1fab25053d03..7bdb00b5aeb2092bf5eb70fcc25fae4b239a59c0 100644 (file)
@@ -2613,7 +2613,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
        case ZFCP_ERP_STEP_UNINITIALIZED:
        case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
        case ZFCP_ERP_STEP_PORT_CLOSING:
-               if (adapter->fc_topology == FSF_TOPO_P2P) {
+               if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) {
                        if (port->wwpn != adapter->peer_wwpn) {
                                ZFCP_LOG_NORMAL("Failed to open port 0x%016Lx "
                                                "on adapter %s.\nPeer WWPN "
index 59587951c847cae2a6eb48baadaa3d64ba0136b4..cbfab09899c89ca7104dd3bfb4abc8c28f5e279b 100644 (file)
@@ -964,6 +964,40 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
                                        | ZFCP_STATUS_COMMON_ERP_FAILED);
                break;
 
+       case FSF_STATUS_READ_NOTIFICATION_LOST:
+               ZFCP_LOG_NORMAL("Unsolicited status notification(s) lost: "
+                               "adapter %s%s%s%s%s%s%s%s%s\n",
+                               zfcp_get_busid_by_adapter(adapter),
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_INCOMING_ELS) ?
+                                       ", incoming ELS" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_SENSE_DATA) ?
+                                       ", sense data" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_LINK_STATUS) ?
+                                       ", link status change" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_PORT_CLOSED) ?
+                                       ", port close" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD) ?
+                                       ", bit error exception" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_ACT_UPDATED) ?
+                                       ", ACT update" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_ACT_HARDENED) ?
+                                       ", ACT hardening" : "",
+                               (status_buffer->status_subtype &
+                                       FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT) ?
+                                       ", adapter feature change" : "");
+
+               if (status_buffer->status_subtype &
+                   FSF_STATUS_READ_SUB_ACT_UPDATED)
+                       zfcp_erp_adapter_access_changed(adapter);
+               break;
+
        case FSF_STATUS_READ_CFDC_UPDATED:
                ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n",
                              zfcp_get_busid_by_adapter(adapter));
@@ -1954,6 +1988,7 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
        erp_action->fsf_req->qtcb->bottom.config.feature_selection =
                        FSF_FEATURE_CFDC |
                        FSF_FEATURE_LUN_SHARING |
+                       FSF_FEATURE_NOTIFICATION_LOST |
                        FSF_FEATURE_UPDATE_ALERT;
 
        /* start QDIO request for this FSF request */
@@ -2008,27 +2043,30 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
                fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
                fc_host_speed(shost) = bottom->fc_link_speed;
                fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
-               adapter->fc_topology = bottom->fc_topology;
                adapter->hydra_version = bottom->adapter_type;
-               if (adapter->physical_wwpn == 0)
-                       adapter->physical_wwpn = fc_host_port_name(shost);
-               if (adapter->physical_s_id == 0)
-                       adapter->physical_s_id = fc_host_port_id(shost);
+               if (fc_host_permanent_port_name(shost) == -1)
+                       fc_host_permanent_port_name(shost) =
+                               fc_host_port_name(shost);
+               if (bottom->fc_topology == FSF_TOPO_P2P) {
+                       adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
+                       adapter->peer_wwpn = bottom->plogi_payload.wwpn;
+                       adapter->peer_wwnn = bottom->plogi_payload.wwnn;
+                       fc_host_port_type(shost) = FC_PORTTYPE_PTP;
+               } else if (bottom->fc_topology == FSF_TOPO_FABRIC)
+                       fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+               else if (bottom->fc_topology == FSF_TOPO_AL)
+                       fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+               else
+                       fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
        } else {
                fc_host_node_name(shost) = 0;
                fc_host_port_name(shost) = 0;
                fc_host_port_id(shost) = 0;
                fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
-               adapter->fc_topology = 0;
+               fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
                adapter->hydra_version = 0;
        }
 
-       if (adapter->fc_topology == FSF_TOPO_P2P) {
-               adapter->peer_d_id = bottom->peer_d_id & ZFCP_DID_MASK;
-               adapter->peer_wwpn = bottom->plogi_payload.wwpn;
-               adapter->peer_wwnn = bottom->plogi_payload.wwnn;
-       }
-
        if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) {
                adapter->hardware_version = bottom->hardware_version;
                memcpy(fc_host_serial_number(shost), bottom->serial_number,
@@ -2097,8 +2135,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1))
                        return -EIO;
 
-               switch (adapter->fc_topology) {
-               case FSF_TOPO_P2P:
+               switch (fc_host_port_type(adapter->scsi_host)) {
+               case FC_PORTTYPE_PTP:
                        ZFCP_LOG_NORMAL("Point-to-Point fibrechannel "
                                        "configuration detected at adapter %s\n"
                                        "Peer WWNN 0x%016llx, "
@@ -2111,7 +2149,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                        debug_text_event(fsf_req->adapter->erp_dbf, 0,
                                         "top-p-to-p");
                        break;
-               case FSF_TOPO_AL:
+               case FC_PORTTYPE_NLPORT:
                        ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
                                        "topology detected at adapter %s "
                                        "unsupported, shutting down adapter\n",
@@ -2120,7 +2158,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                                         "top-al");
                        zfcp_erp_adapter_shutdown(adapter, 0);
                        return -EIO;
-               case FSF_TOPO_FABRIC:
+               case FC_PORTTYPE_NPORT:
                        ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
                                      "network detected at adapter %s.\n",
                                      zfcp_get_busid_by_adapter(adapter));
@@ -2133,7 +2171,6 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
                                        "of a type known to the zfcp "
                                        "driver, shutting down adapter\n",
                                        zfcp_get_busid_by_adapter(adapter));
-                       adapter->fc_topology = FSF_TOPO_ERROR;
                        debug_text_exception(fsf_req->adapter->erp_dbf, 0,
                                             "unknown-topo");
                        zfcp_erp_adapter_shutdown(adapter, 0);
@@ -2293,14 +2330,13 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
                data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
                if (data)
                        memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
-               if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) {
-                       adapter->physical_wwpn = bottom->wwpn;
-                       adapter->physical_s_id = bottom->fc_port_id;
-               } else {
-                       adapter->physical_wwpn = fc_host_port_name(shost);
-                       adapter->physical_s_id = fc_host_port_id(shost);
-               }
+               if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
+                       fc_host_permanent_port_name(shost) = bottom->wwpn;
+               else
+                       fc_host_permanent_port_name(shost) =
+                               fc_host_port_name(shost);
                fc_host_maxframe_size(shost) = bottom->maximum_frame_size;
+               fc_host_supported_speeds(shost) = bottom->supported_speed;
                break;
 
        case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE:
index 48719f0559527b93eef93c442087d6517bc5f9fd..e734415cae6d631c28654f3135711de2e093b7c5 100644 (file)
 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD    0x00000004
 #define FSF_STATUS_READ_LINK_DOWN              0x00000005
 #define FSF_STATUS_READ_LINK_UP                0x00000006
+#define FSF_STATUS_READ_NOTIFICATION_LOST      0x00000009
 #define FSF_STATUS_READ_CFDC_UPDATED           0x0000000A
 #define FSF_STATUS_READ_CFDC_HARDENED          0x0000000B
 #define FSF_STATUS_READ_FEATURE_UPDATE_ALERT   0x0000000C
 #define FSF_STATUS_READ_SUB_FDISC_FAILED       0x00000001
 #define FSF_STATUS_READ_SUB_FIRMWARE_UPDATE    0x00000002
 
+/* status subtypes for unsolicited status notification lost */
+#define FSF_STATUS_READ_SUB_INCOMING_ELS       0x00000001
+#define FSF_STATUS_READ_SUB_SENSE_DATA         0x00000002
+#define FSF_STATUS_READ_SUB_LINK_STATUS                0x00000004
+#define FSF_STATUS_READ_SUB_PORT_CLOSED                0x00000008
+#define FSF_STATUS_READ_SUB_BIT_ERROR_THRESHOLD        0x00000010
+#define FSF_STATUS_READ_SUB_ACT_UPDATED                0x00000020
+#define FSF_STATUS_READ_SUB_ACT_HARDENED       0x00000040
+#define FSF_STATUS_READ_SUB_FEATURE_UPDATE_ALERT 0x00000080
+
 /* status subtypes for CFDC */
 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE        0x00000002
 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F
 #define FSF_TOPO_P2P                           0x00000001
 #define FSF_TOPO_FABRIC                                0x00000002
 #define FSF_TOPO_AL                            0x00000003
-#define FSF_TOPO_FABRIC_VIRT                   0x00000004
 
 /* data direction for FCP commands */
 #define FSF_DATADIR_WRITE                      0x00000001
 /* channel features */
 #define FSF_FEATURE_CFDC                       0x00000002
 #define FSF_FEATURE_LUN_SHARING                        0x00000004
+#define FSF_FEATURE_NOTIFICATION_LOST          0x00000008
 #define FSF_FEATURE_HBAAPI_MANAGEMENT           0x00000010
 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS        0x00000020
 #define FSF_FEATURE_UPDATE_ALERT               0x00000100
index 66608d13a63497b40c4b6002bfad94d30c014728..3c2cbcccbf54c559598e663cc5caa522b2f42f55 100644 (file)
@@ -49,8 +49,6 @@ static int zfcp_task_management_function(struct zfcp_unit *, u8,
 
 static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
                                          scsi_lun_t);
-static struct zfcp_port *zfcp_port_lookup(struct zfcp_adapter *, int,
-                                         scsi_id_t);
 
 static struct device_attribute *zfcp_sysfs_sdev_attrs[];
 
@@ -406,18 +404,6 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id,
        return retval;
 }
 
-static struct zfcp_port *
-zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
-{
-       struct zfcp_port *port;
-
-       list_for_each_entry(port, &adapter->port_list_head, list) {
-               if (port->rport && (id == port->rport->scsi_target_id))
-                       return port;
-       }
-       return (struct zfcp_port *) NULL;
-}
-
 /**
  * zfcp_scsi_eh_abort_handler - abort the specified SCSI command
  * @scpnt: pointer to scsi_cmnd to be aborted 
@@ -731,70 +717,164 @@ zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
 /*
  * Support functions for FC transport class
  */
-static void
-zfcp_get_port_id(struct scsi_target *starget)
+static struct fc_host_statistics*
+zfcp_init_fc_host_stats(struct zfcp_adapter *adapter)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
-       struct zfcp_port *port;
-       unsigned long flags;
+       struct fc_host_statistics *fc_stats;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       port = zfcp_port_lookup(adapter, starget->channel, starget->id);
-       if (port)
-               fc_starget_port_id(starget) = port->d_id;
-       else
-               fc_starget_port_id(starget) = -1;
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       if (!adapter->fc_stats) {
+               fc_stats = kmalloc(sizeof(*fc_stats), GFP_KERNEL);
+               if (!fc_stats)
+                       return NULL;
+               adapter->fc_stats = fc_stats; /* freed in adater_dequeue */
+       }
+       memset(adapter->fc_stats, 0, sizeof(*adapter->fc_stats));
+       return adapter->fc_stats;
 }
 
 static void
-zfcp_get_port_name(struct scsi_target *starget)
+zfcp_adjust_fc_host_stats(struct fc_host_statistics *fc_stats,
+                         struct fsf_qtcb_bottom_port *data,
+                         struct fsf_qtcb_bottom_port *old)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
-       struct zfcp_port *port;
-       unsigned long flags;
+       fc_stats->seconds_since_last_reset = data->seconds_since_last_reset -
+               old->seconds_since_last_reset;
+       fc_stats->tx_frames = data->tx_frames - old->tx_frames;
+       fc_stats->tx_words = data->tx_words - old->tx_words;
+       fc_stats->rx_frames = data->rx_frames - old->rx_frames;
+       fc_stats->rx_words = data->rx_words - old->rx_words;
+       fc_stats->lip_count = data->lip - old->lip;
+       fc_stats->nos_count = data->nos - old->nos;
+       fc_stats->error_frames = data->error_frames - old->error_frames;
+       fc_stats->dumped_frames = data->dumped_frames - old->dumped_frames;
+       fc_stats->link_failure_count = data->link_failure - old->link_failure;
+       fc_stats->loss_of_sync_count = data->loss_of_sync - old->loss_of_sync;
+       fc_stats->loss_of_signal_count = data->loss_of_signal -
+               old->loss_of_signal;
+       fc_stats->prim_seq_protocol_err_count = data->psp_error_counts -
+               old->psp_error_counts;
+       fc_stats->invalid_tx_word_count = data->invalid_tx_words -
+               old->invalid_tx_words;
+       fc_stats->invalid_crc_count = data->invalid_crcs - old->invalid_crcs;
+       fc_stats->fcp_input_requests = data->input_requests -
+               old->input_requests;
+       fc_stats->fcp_output_requests = data->output_requests -
+               old->output_requests;
+       fc_stats->fcp_control_requests = data->control_requests -
+               old->control_requests;
+       fc_stats->fcp_input_megabytes = data->input_mb - old->input_mb;
+       fc_stats->fcp_output_megabytes = data->output_mb - old->output_mb;
+}
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       port = zfcp_port_lookup(adapter, starget->channel, starget->id);
-       if (port)
-               fc_starget_port_name(starget) = port->wwpn;
-       else
-               fc_starget_port_name(starget) = -1;
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+static void
+zfcp_set_fc_host_stats(struct fc_host_statistics *fc_stats,
+                      struct fsf_qtcb_bottom_port *data)
+{
+       fc_stats->seconds_since_last_reset = data->seconds_since_last_reset;
+       fc_stats->tx_frames = data->tx_frames;
+       fc_stats->tx_words = data->tx_words;
+       fc_stats->rx_frames = data->rx_frames;
+       fc_stats->rx_words = data->rx_words;
+       fc_stats->lip_count = data->lip;
+       fc_stats->nos_count = data->nos;
+       fc_stats->error_frames = data->error_frames;
+       fc_stats->dumped_frames = data->dumped_frames;
+       fc_stats->link_failure_count = data->link_failure;
+       fc_stats->loss_of_sync_count = data->loss_of_sync;
+       fc_stats->loss_of_signal_count = data->loss_of_signal;
+       fc_stats->prim_seq_protocol_err_count = data->psp_error_counts;
+       fc_stats->invalid_tx_word_count = data->invalid_tx_words;
+       fc_stats->invalid_crc_count = data->invalid_crcs;
+       fc_stats->fcp_input_requests = data->input_requests;
+       fc_stats->fcp_output_requests = data->output_requests;
+       fc_stats->fcp_control_requests = data->control_requests;
+       fc_stats->fcp_input_megabytes = data->input_mb;
+       fc_stats->fcp_output_megabytes = data->output_mb;
+}
+
+/**
+ * zfcp_get_fc_host_stats - provide fc_host_statistics for scsi_transport_fc
+ *
+ * assumption: scsi_transport_fc synchronizes calls of
+ *             get_fc_host_stats and reset_fc_host_stats
+ *             (XXX to be checked otherwise introduce locking)
+ */
+static struct fc_host_statistics *
+zfcp_get_fc_host_stats(struct Scsi_Host *shost)
+{
+       struct zfcp_adapter *adapter;
+       struct fc_host_statistics *fc_stats;
+       struct fsf_qtcb_bottom_port *data;
+       int ret;
+
+       adapter = (struct zfcp_adapter *)shost->hostdata[0];
+       fc_stats = zfcp_init_fc_host_stats(adapter);
+       if (!fc_stats)
+               return NULL;
+
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return NULL;
+       memset(data, 0, sizeof(*data));
+
+       ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+       if (ret) {
+               kfree(data);
+               return NULL; /* XXX return zeroed fc_stats? */
+       }
+
+       if (adapter->stats_reset &&
+           ((jiffies/HZ - adapter->stats_reset) <
+            data->seconds_since_last_reset)) {
+               zfcp_adjust_fc_host_stats(fc_stats, data,
+                                         adapter->stats_reset_data);
+       } else
+               zfcp_set_fc_host_stats(fc_stats, data);
+
+       kfree(data);
+       return fc_stats;
 }
 
 static void
-zfcp_get_node_name(struct scsi_target *starget)
+zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
 {
-       struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
-       struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
-       struct zfcp_port *port;
-       unsigned long flags;
+       struct zfcp_adapter *adapter;
+       struct fsf_qtcb_bottom_port *data, *old_data;
+       int ret;
 
-       read_lock_irqsave(&zfcp_data.config_lock, flags);
-       port = zfcp_port_lookup(adapter, starget->channel, starget->id);
-       if (port)
-               fc_starget_node_name(starget) = port->wwnn;
-       else
-               fc_starget_node_name(starget) = -1;
-       read_unlock_irqrestore(&zfcp_data.config_lock, flags);
+       adapter = (struct zfcp_adapter *)shost->hostdata[0];
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return;
+       memset(data, 0, sizeof(*data));
+
+       ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+       if (ret == 0) {
+               adapter->stats_reset = jiffies/HZ;
+               old_data = adapter->stats_reset_data;
+               adapter->stats_reset_data = data; /* finally freed in
+                                                    adater_dequeue */
+               kfree(old_data);
+       }
 }
 
 struct fc_function_template zfcp_transport_functions = {
-       .get_starget_port_id = zfcp_get_port_id,
-       .get_starget_port_name = zfcp_get_port_name,
-       .get_starget_node_name = zfcp_get_node_name,
        .show_starget_port_id = 1,
        .show_starget_port_name = 1,
        .show_starget_node_name = 1,
        .show_rport_supported_classes = 1,
        .show_host_node_name = 1,
        .show_host_port_name = 1,
+       .show_host_permanent_port_name = 1,
        .show_host_supported_classes = 1,
+       .show_host_supported_speeds = 1,
        .show_host_maxframe_size = 1,
        .show_host_serial_number = 1,
+       .get_fc_host_stats = zfcp_get_fc_host_stats,
+       .reset_fc_host_stats = zfcp_reset_fc_host_stats,
+       /* no functions registered for following dynamic attributes but
+          directly set by LLDD */
+       .show_host_port_type = 1,
        .show_host_speed = 1,
        .show_host_port_id = 1,
 };
index 0cd435280e7db00947a8d02d21a536fef5ee9762..9f262250043a5d006e99b0b3850f3a351b4821f1 100644 (file)
 
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_CONFIG
 
-static const char fc_topologies[5][25] = {
-       "<error>",
-       "point-to-point",
-       "fabric",
-       "arbitrated loop",
-       "fabric (virt. adapter)"
-};
-
 /**
  * ZFCP_DEFINE_ADAPTER_ATTR
  * @_name:   name of show attribute
@@ -69,12 +61,8 @@ ZFCP_DEFINE_ADAPTER_ATTR(physical_wwpn, "0x%016llx\n", adapter->physical_wwpn);
 ZFCP_DEFINE_ADAPTER_ATTR(physical_s_id, "0x%06x\n", adapter->physical_s_id);
 ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version);
 ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version);
-ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class);
-ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n",
-                        fc_topologies[adapter->fc_topology]);
 ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n",
                         adapter->hardware_version);
-ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no);
 ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask
                         (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status));
 
@@ -259,9 +247,6 @@ static struct attribute *zfcp_adapter_attrs[] = {
        &dev_attr_physical_s_id.attr,
        &dev_attr_card_version.attr,
        &dev_attr_lic_version.attr,
-       &dev_attr_fc_service_class.attr,
-       &dev_attr_fc_topology.attr,
-       &dev_attr_scsi_host_no.attr,
        &dev_attr_status.attr,
        &dev_attr_hardware_version.attr,
        NULL
index c55e82d91deb103133047d823ce3b122de097271..3924eb38805c5e24cae27b148af445f20ce73477 100644 (file)
@@ -65,8 +65,6 @@ static ssize_t zfcp_sysfs_port_##_name##_show(struct device *dev, struct device_
 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_port_##_name##_show, NULL);
 
 ZFCP_DEFINE_PORT_ATTR(status, "0x%08x\n", atomic_read(&port->status));
-ZFCP_DEFINE_PORT_ATTR(wwnn, "0x%016llx\n", port->wwnn);
-ZFCP_DEFINE_PORT_ATTR(d_id, "0x%06x\n", port->d_id);
 ZFCP_DEFINE_PORT_ATTR(in_recovery, "%d\n", atomic_test_mask
                      (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status));
 ZFCP_DEFINE_PORT_ATTR(access_denied, "%d\n", atomic_test_mask
@@ -245,8 +243,6 @@ static struct attribute *zfcp_port_common_attrs[] = {
        &dev_attr_failed.attr,
        &dev_attr_in_recovery.attr,
        &dev_attr_status.attr,
-       &dev_attr_wwnn.attr,
-       &dev_attr_d_id.attr,
        &dev_attr_access_denied.attr,
        NULL
 };
index 0556642c9e1d5ed7cf94d83bf3ff5e8358df7dd4..2f50815f65c746d386d051545fe540637676ea9b 100644 (file)
@@ -65,7 +65,6 @@ static ssize_t zfcp_sysfs_unit_##_name##_show(struct device *dev, struct device_
 static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_unit_##_name##_show, NULL);
 
 ZFCP_DEFINE_UNIT_ATTR(status, "0x%08x\n", atomic_read(&unit->status));
-ZFCP_DEFINE_UNIT_ATTR(scsi_lun, "0x%x\n", unit->scsi_lun);
 ZFCP_DEFINE_UNIT_ATTR(in_recovery, "%d\n", atomic_test_mask
                      (ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status));
 ZFCP_DEFINE_UNIT_ATTR(access_denied, "%d\n", atomic_test_mask
@@ -138,7 +137,6 @@ static DEVICE_ATTR(failed, S_IWUSR | S_IRUGO, zfcp_sysfs_unit_failed_show,
                   zfcp_sysfs_unit_failed_store);
 
 static struct attribute *zfcp_unit_attrs[] = {
-       &dev_attr_scsi_lun.attr,
        &dev_attr_failed.attr,
        &dev_attr_in_recovery.attr,
        &dev_attr_status.attr,
index 92e6c5639dd3b7ef0793091def7ee6ddcc827619..015db40ad8a46079607b00eb9b13ed4564707aca 100644 (file)
@@ -92,7 +92,6 @@ static struct Aurora_port aurora_port[AURORA_TNPORTS] =  {
 
 /* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/
 static unsigned char * tmp_buf = NULL;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 DECLARE_TASK_QUEUE(tq_aurora);
 
index 3ff74f472249bb638a30933389b9046e75862633..31c4975422729d46a47802e975c58c0cc8d46f6a 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -615,7 +616,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        void __user *argp = (void __user *)arg;
 
        /* Only let one of these through at a time */
-       if (down_interruptible(&tw_dev->ioctl_sem)) {
+       if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) {
                retval = TW_IOCTL_ERROR_OS_EINTR;
                goto out;
        }
@@ -852,7 +853,7 @@ out3:
        /* Now free ioctl buf memory */
        dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
 out2:
-       up(&tw_dev->ioctl_sem);
+       mutex_unlock(&tw_dev->ioctl_lock);
 out:
        return retval;
 } /* End twa_chrdev_ioctl() */
@@ -1182,7 +1183,7 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
        tw_dev->error_sequence_id = 1;
        tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
-       init_MUTEX(&tw_dev->ioctl_sem);
+       mutex_init(&tw_dev->ioctl_lock);
        init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
        retval = 0;
index 46f22cdc82985d91bbad87fe3df4a0e8e090cc5d..1b16d57f0314b239d2833a49c063f26e18c6234f 100644 (file)
@@ -672,7 +672,7 @@ typedef struct TAG_TW_Device_Extension {
        u32                     ioctl_msec;
        int                     chrdev_request_id;
        wait_queue_head_t       ioctl_wqueue;
-       struct semaphore        ioctl_sem;
+       struct mutex            ioctl_lock;
        char                    aen_clobber;
        unsigned short          working_srl;
        unsigned short          working_branch;
index 283f6d25892b9c7d97dfd97fe3643ad12d7d0c47..25f678d0780b2e1bb2dcf12a767b8607739db150 100644 (file)
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -888,7 +889,7 @@ static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
        dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
 
        /* Only let one of these through at a time */
-       if (down_interruptible(&tw_dev->ioctl_sem))
+       if (mutex_lock_interruptible(&tw_dev->ioctl_lock))
                return -EINTR;
 
        /* First copy down the buffer length */
@@ -1029,7 +1030,7 @@ out2:
        /* Now free ioctl buf memory */
        dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
 out:
-       up(&tw_dev->ioctl_sem);
+       mutex_unlock(&tw_dev->ioctl_lock);
        return retval;
 } /* End tw_chrdev_ioctl() */
 
@@ -1270,7 +1271,7 @@ static int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
        tw_dev->pending_tail = TW_Q_START;
        tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
 
-       init_MUTEX(&tw_dev->ioctl_sem);
+       mutex_init(&tw_dev->ioctl_lock);
        init_waitqueue_head(&tw_dev->ioctl_wqueue);
 
        return 0;
index 4f81fc39ec57d7525a506021433aaefec0707702..31fe5ea159205bb15b861a615d39b7405679c728 100644 (file)
@@ -420,7 +420,7 @@ typedef struct TAG_TW_Device_Extension {
        u32                     max_sector_count;
        u32                     aen_count;
        struct Scsi_Host        *host;
-       struct semaphore        ioctl_sem;
+       struct mutex            ioctl_lock;
        unsigned short          aen_queue[TW_Q_LENGTH];
        unsigned char           aen_head;
        unsigned char           aen_tail;
index 9d6040bfa0646ae32283be9f1ffde0e974172594..1c459343292bb6b910cf28322293df912bfb9323 100644 (file)
@@ -2216,6 +2216,7 @@ static int __init BusLogic_init(void)
                HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
                HostAdapter->Bus = ProbeInfo->Bus;
                HostAdapter->Device = ProbeInfo->Device;
+               HostAdapter->PCI_Device = ProbeInfo->PCI_Device;
                HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
                HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
                /*
@@ -2296,7 +2297,7 @@ static int __init BusLogic_init(void)
                                scsi_host_put(Host);
                        } else {
                                BusLogic_InitializeHostStructure(HostAdapter, Host);
-                               scsi_add_host(Host, NULL);
+                               scsi_add_host(Host, HostAdapter->PCI_Device ? &HostAdapter->PCI_Device->dev : NULL);
                                scsi_scan_host(Host);
                                BusLogicHostAdapterCount++;
                        }
index 6e0c059df6a5339da1349164aa59cb46ae5733a8..320e765fa0cd97b873e62b6c805d07c52aab67d1 100644 (file)
@@ -80,7 +80,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o       qlogicfas.o
 obj-$(CONFIG_PCMCIA_QLOGIC)    += qlogicfas408.o
 obj-$(CONFIG_SCSI_QLOGIC_FC)   += qlogicfc.o 
 obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o 
-obj-$(CONFIG_SCSI_QLA2XXX)     += qla2xxx/
+obj-$(CONFIG_SCSI_QLA_FC)      += qla2xxx/
 obj-$(CONFIG_SCSI_LPFC)                += lpfc/
 obj-$(CONFIG_SCSI_PAS16)       += pas16.o
 obj-$(CONFIG_SCSI_SEAGATE)     += seagate.o
diff --git a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README
deleted file mode 100644 (file)
index 4193865..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-AACRAID Driver for Linux (take two)
-
-Introduction
--------------------------
-The aacraid driver adds support for Adaptec (http://www.adaptec.com)
-RAID controllers. This is a major rewrite from the original 
-Adaptec supplied driver. It has signficantly cleaned up both the code
-and the running binary size (the module is less than half the size of
-the original).
-
-Supported Cards/Chipsets
--------------------------
-       Adaptec 2020S
-       Adaptec 2025S
-       Adaptec 2120S
-       Adaptec 2130S
-       Adaptec 2200S
-       Adaptec 2230S
-       Adaptec 2240S
-       Adaptec 2410SA
-       Adaptec 2610SA
-       Adaptec 2810SA
-       Adaptec 21610SA
-       Adaptec 3230S
-       Adaptec 3240S
-       Adaptec 4000SAS
-       Adaptec 4005SAS
-       Adaptec 4800SAS
-       Adaptec 4805SAS
-       Adaptec 5400S
-       Dell PERC 2 Quad Channel
-       Dell PERC 2/Si
-       Dell PERC 3/Si
-       Dell PERC 3/Di
-       Dell CERC 2
-       HP NetRAID-4M
-       Legend S220
-       Legend S230
-       IBM ServeRAID 8i
-       ICP 9014R0
-       ICP 9024R0
-       ICP 9047MA
-       ICP 9087MA
-       ICP 9085LI
-       ICP 5085AU
-
-People
--------------------------
-Alan Cox <alan@redhat.com>
-Christoph Hellwig <hch@infradead.org>  (updates for new-style PCI probing and SCSI host registration,
-                                        small cleanups/fixes)
-Matt Domsch <matt_domsch@dell.com>     (revision ioctl, adapter messages)
-Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
-                                        added new ioctls, changed scsi interface to use new error handler,
-                                        increased the number of fibs and outstanding commands to a container)
-
-                                       (fixed 64bit and 64G memory model, changed confusing naming convention
-                                        where fibs that go to the hardware are consistently called hw_fibs and
-                                        not just fibs like the name of the driver tracking structure)
-Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas. Performance tuning, card failover and bug mitigations.
-
-Original Driver
--------------------------
-Adaptec Unix OEM Product Group
-
-Mailing List
--------------------------
-linux-scsi@vger.kernel.org (Interested parties troll here)
-Also note this is very different to Brian's original driver
-so don't expect him to support it.
-Adaptec does support this driver.  Contact either tech support or Mark Salyzyn.
-
-Original by Brian Boerner February 2001
-Rewritten by Alan Cox, November 2001
index 30fd8d6e3f31081042f56ba897a87bae84fa9dab..66dbb6d2c506afe1ce904b66db2aa76f3b93c72e 100644 (file)
@@ -531,6 +531,13 @@ struct aac_driver_ident
  */
 #define AAC_QUIRK_MASTER 0x0008
 
+/*
+ * Some adapter firmware perform poorly when it must split up scatter gathers
+ * in order to deal with the limits of the underlying CHIM. This limit in this
+ * class of adapters is 17 scatter gather elements.
+ */
+#define AAC_QUIRK_17SG 0x0010
+
 /*
  *     The adapter interface specs all queues to be located in the same
  *     physically contigous block. The host structure that defines the
index ef623bd965f52fade74db0e16e8a7a61f29610f8..4fe79cd7c957664bf8a686b18d46fe490b131d7a 100644 (file)
@@ -85,6 +85,10 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
        if (size < le16_to_cpu(kfib->header.SenderSize))
                size = le16_to_cpu(kfib->header.SenderSize);
        if (size > dev->max_fib_size) {
+               if (size > 2048) {
+                       retval = -EINVAL;
+                       goto cleanup;
+               }
                /* Highjack the hw_fib */
                hw_fib = fibptr->hw_fib;
                hw_fib_pa = fibptr->hw_fib_pa;
index 9b9062f02462534a216e2099ae7fa93d5ea0d3c0..0bf5f9a943e8a548d779b022246d63348f5c3c77 100644 (file)
@@ -200,10 +200,10 @@ static struct aac_driver_ident aac_drivers[] = {
        { aac_rkt_init, "aacraid",  "ADAPTEC ", "Callisto        ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020SA       ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025SA       ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
-       { aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
-       { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1, AAC_QUIRK_17SG }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+       { aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1, AAC_QUIRK_17SG }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1, AAC_QUIRK_17SG }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+       { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1, AAC_QUIRK_17SG }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2026ZCR     ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2610SA      ", 1 }, /* SATA 6Ch (Bearcat) */
        { aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2240S       ", 1 }, /* ASR-2240S (SabreExpress) */
@@ -574,7 +574,15 @@ static ssize_t aac_show_model(struct class_device *class_dev,
        struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
        int len;
 
-       len = snprintf(buf, PAGE_SIZE, "%s\n",
+       if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+               char * cp = dev->supplement_adapter_info.AdapterTypeText;
+               while (*cp && *cp != ' ')
+                       ++cp;
+               while (*cp == ' ')
+                       ++cp;
+               len = snprintf(buf, PAGE_SIZE, "%s\n", cp);
+       } else
+               len = snprintf(buf, PAGE_SIZE, "%s\n",
                  aac_drivers[dev->cardtype].model);
        return len;
 }
@@ -585,7 +593,15 @@ static ssize_t aac_show_vendor(struct class_device *class_dev,
        struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
        int len;
 
-       len = snprintf(buf, PAGE_SIZE, "%s\n",
+       if (dev->supplement_adapter_info.AdapterTypeText[0]) {
+               char * cp = dev->supplement_adapter_info.AdapterTypeText;
+               while (*cp && *cp != ' ')
+                       ++cp;
+               len = snprintf(buf, PAGE_SIZE, "%.*s\n",
+                 (int)(cp - (char *)dev->supplement_adapter_info.AdapterTypeText),
+                 dev->supplement_adapter_info.AdapterTypeText);
+       } else
+               len = snprintf(buf, PAGE_SIZE, "%s\n",
                  aac_drivers[dev->cardtype].vname);
        return len;
 }
@@ -837,6 +853,13 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
                  = (aac->scsi_host_ptr->sg_tablesize * 8) + 112;
        }
 
+       if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
+                       (aac->scsi_host_ptr->sg_tablesize > 17)) {
+               aac->scsi_host_ptr->sg_tablesize = 17;
+               aac->scsi_host_ptr->max_sectors
+                 = (aac->scsi_host_ptr->sg_tablesize * 8) + 112;
+       }
+
        /*
         * Firware printf works only with older firmware.
         */
index ac8de03c9fa2b6f4b0e99f6708c0772743145410..6c2c395554ff3d37b7f7673a01327d59c976a55a 100644 (file)
@@ -42,13 +42,13 @@ config AIC7XXX_CMDS_PER_DEVICE
 config AIC7XXX_RESET_DELAY_MS
        int "Initial bus reset delay in milli-seconds"
        depends on SCSI_AIC7XXX
-       default "15000"
+       default "5000"
        ---help---
        The number of milliseconds to delay after an initial bus reset.
        The bus settle delay following all error recovery actions is
        dictated by the SCSI layer and is not affected by this value.
 
-       Default: 15000 (15 seconds)
+       Default: 5000 (5 seconds)
 
 config AIC7XXX_PROBE_EISA_VL
        bool "Probe for EISA and VL AIC7XXX Adapters"
index 653fb0b42aeac3283a0796336588560b81c5a173..2cfdbef447db6ba7c4f7b774fcce47fe5f53e409 100644 (file)
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#95 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#108 $
  *
  * $FreeBSD$
  */
@@ -75,8 +75,7 @@ struct scb_platform_data;
 #define INITIATOR_WILDCARD     (~0)
 #define        SCB_LIST_NULL           0xFF00
 #define        SCB_LIST_NULL_LE        (ahd_htole16(SCB_LIST_NULL))
-#define QOUTFIFO_ENTRY_VALID 0x8000
-#define QOUTFIFO_ENTRY_VALID_LE (ahd_htole16(0x8000))
+#define QOUTFIFO_ENTRY_VALID 0x80
 #define SCBID_IS_NULL(scbid) (((scbid) & 0xFF00 ) == SCB_LIST_NULL)
 
 #define SCSIID_TARGET(ahd, scsiid)     \
@@ -1053,6 +1052,13 @@ typedef uint8_t ahd_mode_state;
 
 typedef void ahd_callback_t (void *);
 
+struct ahd_completion
+{
+       uint16_t        tag;
+       uint8_t         sg_status;
+       uint8_t         valid_tag;
+};
+
 struct ahd_softc {
        bus_space_tag_t           tags[2];
        bus_space_handle_t        bshs[2];
@@ -1062,6 +1068,7 @@ struct ahd_softc {
        struct scb_data           scb_data;
 
        struct hardware_scb      *next_queued_hscb;
+       struct map_node          *next_queued_hscb_map;
 
        /*
         * SCBs that have been sent to the controller
@@ -1140,16 +1147,23 @@ struct ahd_softc {
        ahd_flag                  flags;
        struct seeprom_config    *seep_config;
 
-       /* Values to store in the SEQCTL register for pause and unpause */
-       uint8_t                   unpause;
-       uint8_t                   pause;
-
        /* Command Queues */
+       struct ahd_completion     *qoutfifo;
        uint16_t                  qoutfifonext;
        uint16_t                  qoutfifonext_valid_tag;
        uint16_t                  qinfifonext;
        uint16_t                  qinfifo[AHD_SCB_MAX];
-       uint16_t                 *qoutfifo;
+
+       /*
+        * Our qfreeze count.  The sequencer compares
+        * this value with its own counter to determine
+        * whether to allow selections to occur.
+        */
+       uint16_t                  qfreeze_cnt;
+
+       /* Values to store in the SEQCTL register for pause and unpause */
+       uint8_t                   unpause;
+       uint8_t                   pause;
 
        /* Critical Section Data */
        struct cs                *critical_sections;
@@ -1197,8 +1211,7 @@ struct ahd_softc {
         */
        bus_dma_tag_t             parent_dmat;
        bus_dma_tag_t             shared_data_dmat;
-       bus_dmamap_t              shared_data_dmamap;
-       dma_addr_t                shared_data_busaddr;
+       struct map_node           shared_data_map;
 
        /* Information saved through suspend/resume cycles */
        struct ahd_suspend_state  suspend_state;
@@ -1296,9 +1309,9 @@ struct ahd_devinfo {
 };
 
 /****************************** PCI Structures ********************************/
-#define AHD_PCI_IOADDR0        PCIR_MAPS       /* I/O BAR*/
-#define AHD_PCI_MEMADDR        (PCIR_MAPS + 4) /* Memory BAR */
-#define AHD_PCI_IOADDR1        (PCIR_MAPS + 12)/* Second I/O BAR */
+#define AHD_PCI_IOADDR0        PCIR_BAR(0)     /* I/O BAR*/
+#define AHD_PCI_MEMADDR        PCIR_BAR(1)     /* Memory BAR */
+#define AHD_PCI_IOADDR1        PCIR_BAR(3)     /* Second I/O BAR */
 
 typedef int (ahd_device_setup_t)(struct ahd_softc *);
 
index cca58edc8648c4e68256a26d0eeb173f34bb0f39..3a3204703b155f374a7cf99cb86dcb2b028f8c05 100644 (file)
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -65,13 +65,6 @@ VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $"
                mvi     MODE_PTR, MK_MODE(src, dst);                    \
        }
 
-#define TOGGLE_DFF_MODE                                                        \
-       if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {                      \
-               call    toggle_dff_mode_work_around;                    \
-       } else {                                                        \
-               xor     MODE_PTR, MK_MODE(M_DFF1, M_DFF1);              \
-       }
-       
 #define RESTORE_MODE(mode)                                             \
        if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {                      \
                mov     mode call set_mode_work_around;                 \
@@ -1199,7 +1192,7 @@ register TARGPCISTAT {
 
 /*
  * LQ Packet In
- * The last LQ Packet received
+ * The last LQ Packet recieved
  */
 register LQIN {
        address                 0x020
@@ -3542,10 +3535,34 @@ scratch_ram {
        COMPLETE_DMA_SCB_HEAD {
                size            2
        }
-       /* Counting semaphore to prevent new select-outs */
+       /*
+        * tail of list of SCBs that have
+        * completed but need to be uploaded
+        * to the host prior to being completed.
+        */
+       COMPLETE_DMA_SCB_TAIL {
+               size            2
+       }
+       /*
+        * head of list of SCBs that have
+        * been uploaded to the host, but cannot
+        * be completed until the QFREEZE is in
+        * full effect (i.e. no selections pending).
+        */
+       COMPLETE_ON_QFREEZE_HEAD {
+               size            2
+       }
+       /*
+        * Counting semaphore to prevent new select-outs
+        * The queue is frozen so long as the sequencer
+        * and kernel freeze counts differ.
+        */
        QFREEZE_COUNT {
                size            2
        }
+       KERNEL_QFREEZE_COUNT {
+               size            2
+       }
        /*
         * Mode to restore on legacy idle loop exit.
         */
@@ -3624,6 +3641,17 @@ scratch_ram {
        QOUTFIFO_ENTRY_VALID_TAG {
                size            1
        }
+       /*
+        * Kernel and sequencer offsets into the queue of
+        * incoming target mode command descriptors.  The
+        * queue is full when the KERNEL_TQINPOS == TQINPOS.
+        */
+       KERNEL_TQINPOS {
+               size            1
+       }
+       TQINPOS {                
+               size            1
+       }
        /*
         * Base address of our shared data with the kernel driver in host
         * memory.  This includes the qoutfifo and target mode
@@ -3639,17 +3667,6 @@ scratch_ram {
        QOUTFIFO_NEXT_ADDR {
                size            4
        }
-       /*
-        * Kernel and sequencer offsets into the queue of
-        * incoming target mode command descriptors.  The
-        * queue is full when the KERNEL_TQINPOS == TQINPOS.
-        */
-       KERNEL_TQINPOS {
-               size            1
-       }
-       TQINPOS {                
-               size            1
-       }
        ARG_1 {
                size            1
                mask    SEND_MSG                0x80
@@ -3951,6 +3968,7 @@ const SG_PREFETCH_ADDR_MASK download
 const SG_SIZEOF download
 const PKT_OVERRUN_BUFOFFSET download
 const SCB_TRANSFER_SIZE        download
+const CACHELINE_MASK download
 
 /*
  * BIOS SCB offsets
index 65339bc1ca99cd3f9b960703aa2b5e3c1520d452..bef1f9d369b6b90779d13f3ee54a53c7a105bb3a 100644 (file)
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#99 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -68,13 +68,47 @@ no_error_set:
        }
        SET_MODE(M_SCSI, M_SCSI)
        test    SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus;
-       test    SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus;
+       test    SEQ_FLAGS2, SELECTOUT_QFROZEN jz check_waiting_list;
+       /*
+        * If the kernel has caught up with us, thaw the queue.
+        */
+       mov     A, KERNEL_QFREEZE_COUNT;
+       cmp     QFREEZE_COUNT, A jne check_frozen_completions;
+       mov     A, KERNEL_QFREEZE_COUNT[1];
+       cmp     QFREEZE_COUNT[1], A jne check_frozen_completions;
+       and     SEQ_FLAGS2, ~SELECTOUT_QFROZEN;
+       jmp     check_waiting_list;
+check_frozen_completions:
+       test    SSTAT0, SELDO|SELINGO jnz idle_loop_checkbus;
+BEGIN_CRITICAL;
+       /*
+        * If we have completions stalled waiting for the qfreeze
+        * to take effect, move them over to the complete_scb list
+        * now that no selections are pending.
+        */
+       cmp     COMPLETE_ON_QFREEZE_HEAD[1],SCB_LIST_NULL je idle_loop_checkbus;
+       /*
+        * Find the end of the qfreeze list.  The first element has
+        * to be treated specially.
+        */
+       bmov    SCBPTR, COMPLETE_ON_QFREEZE_HEAD, 2;
+       cmp     SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je join_lists;
+       /*
+        * Now the normal loop.
+        */
+       bmov    SCBPTR, SCB_NEXT_COMPLETE, 2;
+       cmp     SCB_NEXT_COMPLETE[1], SCB_LIST_NULL jne . - 1;
+join_lists:
+       bmov    SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
+       bmov    COMPLETE_SCB_HEAD, COMPLETE_ON_QFREEZE_HEAD, 2;
+       mvi     COMPLETE_ON_QFREEZE_HEAD[1], SCB_LIST_NULL;
+       jmp     idle_loop_checkbus;
+check_waiting_list:
        cmp     WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus;
        /*
         * ENSELO is cleared by a SELDO, so we must test for SELDO
         * one last time.
         */
-BEGIN_CRITICAL;
        test    SSTAT0, SELDO jnz select_out;
 END_CRITICAL;
        call    start_selection;
@@ -90,6 +124,13 @@ idle_loop_check_nonpackreq:
        test    SSTAT2, NONPACKREQ jz . + 2;
        call    unexpected_nonpkt_phase_find_ctxt;
        if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+               /*
+                * On Rev A. hardware, the busy LED is only
+                * turned on automaically during selections
+                * and re-selections.  Make the LED status
+                * more useful by forcing it to be on so
+                * long as one of our data FIFOs is active.
+                */
                and     A, FIFO0FREE|FIFO1FREE, DFFSTAT;
                cmp     A, FIFO0FREE|FIFO1FREE jne . + 3;
                and     SBLKCTL, ~DIAGLEDEN|DIAGLEDON;
@@ -101,9 +142,9 @@ idle_loop_check_nonpackreq:
        call    idle_loop_cchan;
        jmp     idle_loop;
 
-BEGIN_CRITICAL;
 idle_loop_gsfifo:
        SET_MODE(M_SCSI, M_SCSI)
+BEGIN_CRITICAL;
 idle_loop_gsfifo_in_scsi_mode:
        test    LQISTAT2, LQIGSAVAIL jz return;
        /*
@@ -152,11 +193,15 @@ END_CRITICAL;
 
 idle_loop_service_fifos:
        SET_MODE(M_DFF0, M_DFF0)
+BEGIN_CRITICAL;
        test    LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo;
        call    longjmp;
+END_CRITICAL;
 idle_loop_next_fifo:
        SET_MODE(M_DFF1, M_DFF1)
+BEGIN_CRITICAL;
        test    LONGJMP_ADDR[1], INVALID_ADDR jz longjmp;
+END_CRITICAL;
 return:
        ret;
 
@@ -170,7 +215,6 @@ BEGIN_CRITICAL;
        test    CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle;
        test    CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog;
        test    CCSCBCTL, CCSCBDONE jz return;
-END_CRITICAL;
        /* FALLTHROUGH */
 scbdma_tohost_done:
        test    CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
@@ -180,26 +224,18 @@ scbdma_tohost_done:
         * bad SCSI status (currently only for underruns), we
         * queue the SCB for normal completion.  Otherwise, we
         * wait until any select-out activity has halted, and
-        * then notify the host so that the transaction can be
-        * dealt with.
+        * then queue the completion.
         */
-       test    SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host;
        and     CCSCBCTL, ~(CCARREN|CCSCBEN);
        bmov    COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+       cmp     SCB_NEXT_COMPLETE[1], SCB_LIST_NULL jne . + 2;
+       mvi     COMPLETE_DMA_SCB_TAIL[1], SCB_LIST_NULL;
+       test    SCB_SCSI_STATUS, 0xff jz scbdma_queue_completion;
+       bmov    SCB_NEXT_COMPLETE, COMPLETE_ON_QFREEZE_HEAD, 2;
+       bmov    COMPLETE_ON_QFREEZE_HEAD, SCBPTR, 2 ret;
+scbdma_queue_completion:
        bmov    SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
        bmov    COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
-scbdma_notify_host:
-       SET_MODE(M_SCSI, M_SCSI)
-       test    SCSISEQ0, ENSELO jnz return;
-       test    SSTAT0, (SELDO|SELINGO) jnz return;
-       SET_MODE(M_CCHAN, M_CCHAN)
-       /*
-        * Remove SCB and notify host.
-        */
-       and     CCSCBCTL, ~(CCARREN|CCSCBEN);
-       bmov    COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
-       SET_SEQINTCODE(BAD_SCB_STATUS)
-       ret;
 fill_qoutfifo_dmadone:
        and     CCSCBCTL, ~(CCARREN|CCSCBEN);
        call    qoutfifo_updated;
@@ -208,6 +244,7 @@ fill_qoutfifo_dmadone:
        test    QOFF_CTLSTA, SDSCB_ROLLOVR jz return;
        bmov    QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4;
        xor     QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret;
+END_CRITICAL;
 
 qoutfifo_updated:
        /*
@@ -324,14 +361,15 @@ fill_qoutfifo:
         * Keep track of the SCBs we are dmaing just
         * in case the DMA fails or is aborted.
         */
-       mov     A, QOUTFIFO_ENTRY_VALID_TAG;
        bmov    COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2;
        mvi     CCSCBCTL, CCSCBRESET;
        bmov    SCBHADDR, QOUTFIFO_NEXT_ADDR, 4;
+       mov     A, QOUTFIFO_NEXT_ADDR;
        bmov    SCBPTR, COMPLETE_SCB_HEAD, 2;
 fill_qoutfifo_loop:
-       mov     CCSCBRAM, SCBPTR;
-       or      CCSCBRAM, A, SCBPTR[1];
+       bmov    CCSCBRAM, SCBPTR, 2;
+       mov     CCSCBRAM, SCB_SGPTR[0];
+       mov     CCSCBRAM, QOUTFIFO_ENTRY_VALID_TAG;
        mov     NONE, SDSCB_QOFF;
        inc     INT_COALESCING_CMDCOUNT;
        add     CMDS_PENDING, -1;
@@ -339,6 +377,18 @@ fill_qoutfifo_loop:
        cmp     SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done;
        cmp     CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done;
        test    QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done;
+       /*
+        * Don't cross an ADB or Cachline boundary when DMA'ing
+        * completion entries.  In PCI mode, at least in 32/33
+        * configurations, the SCB DMA engine may lose its place
+        * in the data-stream should the target force a retry on
+        * something other than an 8byte aligned boundary. In
+        * PCI-X mode, we do this to avoid split transactions since
+        * many chipsets seem to be unable to format proper split
+        * completions to continue the data transfer.
+        */
+       add     SINDEX, A, CCSCBADDR;
+       test    SINDEX, CACHELINE_MASK jz fill_qoutfifo_done;
        bmov    SCBPTR, SCB_NEXT_COMPLETE, 2;
        jmp     fill_qoutfifo_loop;
 fill_qoutfifo_done:
@@ -354,7 +404,6 @@ dma_complete_scb:
        bmov    SCBPTR, COMPLETE_DMA_SCB_HEAD, 2;
        bmov    SCBHADDR, SCB_BUSADDR, 4;
        mvi     CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb;
-END_CRITICAL;
 
 /*
  * Either post or fetch an SCB from host memory.  The caller
@@ -371,9 +420,19 @@ dma_scb:
        mvi     SCBHCNT, SCB_TRANSFER_SIZE;
        mov     CCSCBCTL, SINDEX ret;
 
-BEGIN_CRITICAL;
 setjmp:
-       bmov    LONGJMP_ADDR, STACK, 2 ret;
+       /*
+        * At least on the A, a return in the same
+        * instruction as the bmov results in a return
+        * to the caller, not to the new address at the
+        * top of the stack.  Since we want the latter
+        * (we use setjmp to register a handler from an
+        * interrupt context but not invoke that handler
+        * until we return to our idle loop), use a
+        * separate ret instruction.
+        */
+       bmov    LONGJMP_ADDR, STACK, 2;
+       ret;
 setjmp_inline:
        bmov    LONGJMP_ADDR, STACK, 2;
 longjmp:
@@ -392,11 +451,6 @@ set_mode_work_around:
        mvi     SEQINTCTL, INTVEC1DSL;
        mov     MODE_PTR, SINDEX;
        clr     SEQINTCTL ret;
-
-toggle_dff_mode_work_around:
-       mvi     SEQINTCTL, INTVEC1DSL;
-       xor     MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
-       clr     SEQINTCTL ret;
 }
 
 
@@ -490,6 +544,21 @@ allocate_fifo1:
 SET_SRC_MODE   M_SCSI;
 SET_DST_MODE   M_SCSI;
 select_in:
+       if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+               /*
+                * On Rev A. hardware, the busy LED is only
+                * turned on automaically during selections
+                * and re-selections.  Make the LED status
+                * more useful by forcing it to be on from
+                * the point of selection until our idle
+                * loop determines that neither of our FIFOs
+                * are busy.  This handles the non-packetized
+                * case nicely as we will not return to the
+                * idle loop until the busfree at the end of
+                * each transaction.
+                */
+               or      SBLKCTL, DIAGLEDEN|DIAGLEDON;
+       }
        if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
                /*
                 * Test to ensure that the bus has not
@@ -528,6 +597,21 @@ SET_SRC_MODE       M_SCSI;
 SET_DST_MODE   M_SCSI;
 select_out:
 BEGIN_CRITICAL;
+       if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+               /*
+                * On Rev A. hardware, the busy LED is only
+                * turned on automaically during selections
+                * and re-selections.  Make the LED status
+                * more useful by forcing it to be on from
+                * the point of re-selection until our idle
+                * loop determines that neither of our FIFOs
+                * are busy.  This handles the non-packetized
+                * case nicely as we will not return to the
+                * idle loop until the busfree at the end of
+                * each transaction.
+                */
+               or      SBLKCTL, DIAGLEDEN|DIAGLEDON;
+       }
        /* Clear out all SCBs that have been successfully sent. */
        if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) {
                /*
@@ -1000,15 +1084,9 @@ not_found_ITloop:
 /*
  * We received a "command complete" message.  Put the SCB on the complete
  * queue and trigger a completion interrupt via the idle loop.  Before doing
- * so, check to see if there
- * is a residual or the status byte is something other than STATUS_GOOD (0).
- * In either of these conditions, we upload the SCB back to the host so it can
- * process this information.  In the case of a non zero status byte, we 
- * additionally interrupt the kernel driver synchronously, allowing it to
- * decide if sense should be retrieved.  If the kernel driver wishes to request
- * sense, it will fill the kernel SCB with a request sense command, requeue
- * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
- * RETURN_1 to SEND_SENSE.
+ * so, check to see if there is a residual or the status byte is something
+ * other than STATUS_GOOD (0).  In either of these conditions, we upload the
+ * SCB back to the host so it can process this information.
  */
 mesgin_complete:
 
@@ -1053,6 +1131,7 @@ complete_nomsg:
        call    queue_scb_completion;
        jmp     await_busfree;
 
+BEGIN_CRITICAL;
 freeze_queue:
        /* Cancel any pending select-out. */
        test    SSTAT0, SELDO|SELINGO jnz . + 2;
@@ -1063,6 +1142,7 @@ freeze_queue:
        adc     QFREEZE_COUNT[1], A;
        or      SEQ_FLAGS2, SELECTOUT_QFROZEN;
        mov     A, ACCUM_SAVE ret;
+END_CRITICAL;
 
 /*
  * Complete the current FIFO's SCB if data for this same
@@ -1085,8 +1165,10 @@ queue_scb_completion:
        test    SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
        test    SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
 complete:
+BEGIN_CRITICAL;
        bmov    SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
        bmov    COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
+END_CRITICAL;
 bad_status:
        cmp     SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb;
        call    freeze_queue;
@@ -1097,9 +1179,18 @@ upload_scb:
         * it on the host.
         */
        bmov    SCB_TAG, SCBPTR, 2;
-       bmov    SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2;
+BEGIN_CRITICAL;
+       or      SCB_SGPTR, SG_STATUS_VALID;
+       mvi     SCB_NEXT_COMPLETE[1], SCB_LIST_NULL;
+       cmp     COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne add_dma_scb_tail;
        bmov    COMPLETE_DMA_SCB_HEAD, SCBPTR, 2;
-       or      SCB_SGPTR, SG_STATUS_VALID ret;
+       bmov    COMPLETE_DMA_SCB_TAIL, SCBPTR, 2 ret;
+add_dma_scb_tail:
+       bmov    REG0, SCBPTR, 2;
+       bmov    SCBPTR, COMPLETE_DMA_SCB_TAIL, 2;
+       bmov    SCB_NEXT_COMPLETE, REG0, 2;
+       bmov    COMPLETE_DMA_SCB_TAIL, REG0, 2 ret;
+END_CRITICAL;
 
 /*
  * Is it a disconnect message?  Set a flag in the SCB to remind us
@@ -1146,8 +1237,18 @@ SET_DST_MODE     M_DFF1;
 await_busfree_clrchn:
        mvi     DFFSXFRCTL, CLRCHN;
 await_busfree_not_m_dff:
-       call    clear_target_state;
+       /* clear target specific flags */
+       mvi     SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT;
        test    SSTAT1,REQINIT|BUSFREE  jz .;
+       /*
+        * We only set BUSFREE status once either a new
+        * phase has been detected or we are really
+        * BUSFREE.  This allows the driver to know
+        * that we are active on the bus even though
+        * no identified transaction exists should a
+        * timeout occur while awaiting busfree.
+        */
+       mvi     LASTPHASE, P_BUSFREE;
        test    SSTAT1, BUSFREE jnz idle_loop;
        SET_SEQINTCODE(MISSED_BUSFREE)
 
@@ -1202,11 +1303,6 @@ msgin_rdptrs_get_fifo:
        call    allocate_fifo;
        jmp     mesgin_done;
 
-clear_target_state:
-       mvi     LASTPHASE, P_BUSFREE;
-       /* clear target specific flags */
-       mvi     SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
-
 phase_lock:     
        if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) {
                /*
@@ -1297,6 +1393,47 @@ service_fifo:
        /* Are we actively fetching segments? */
        test    CCSGCTL, CCSGENACK jnz return;
 
+       /*
+        * Should the other FIFO get the S/G cache first?  If
+        * both FIFOs have been allocated since we last checked
+        * any FIFO, it is important that we service a FIFO
+        * that is not actively on the bus first.  This guarantees
+        * that a FIFO will be freed to handle snapshot requests for
+        * any FIFO that is still on the bus.  Chips with RTI do not
+        * perform snapshots, so don't bother with this test there.
+        */
+       if ((ahd->features & AHD_RTI) == 0) {
+               /*
+                * If we're not still receiving SCSI data,
+                * it is safe to allocate the S/G cache to
+                * this FIFO.
+                */
+               test    DFCNTRL, SCSIEN jz idle_sgfetch_start;
+
+               /*
+                * Switch to the other FIFO.  Non-RTI chips
+                * also have the "set mode" bug, so we must
+                * disable interrupts during the switch.
+                */
+               mvi     SEQINTCTL, INTVEC1DSL;
+               xor     MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+
+               /*
+                * If the other FIFO needs loading, then it
+                * must not have claimed the S/G cache yet
+                * (SG_CACHE_AVAIL would have been cleared in
+                * the orginal FIFO mode and we test this above).
+                * Return to the idle loop so we can process the
+                * FIFO not currently on the bus first.
+                */
+               test    SG_STATE, LOADING_NEEDED jz idle_sgfetch_okay;
+               clr     SEQINTCTL ret;
+idle_sgfetch_okay:
+               xor     MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+               clr     SEQINTCTL;
+       }
+
+idle_sgfetch_start:
        /*
         * We fetch a "cacheline aligned" and sized amount of data
         * so we don't end up referencing a non-existant page.
@@ -1308,7 +1445,7 @@ service_fifo:
        mvi     SGHCNT, SG_PREFETCH_CNT;
        if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) {
                /*
-                * Need two instruction between "touches" of SGHADDR.
+                * Need two instructions between "touches" of SGHADDR.
                 */
                nop;
        }
@@ -1658,7 +1795,7 @@ export seq_isr:
                 * savepointer in the current FIFO.  We do this so that
                 * a pending CTXTDONE or SAVEPTR is visible in the active
                 * FIFO.  This status is the only way we can detect if we
-                * have lost the race (e.g. host paused us) and our attepts
+                * have lost the race (e.g. host paused us) and our attempts
                 * to disable the channel occurred after all REQs were
                 * already seen and acked (REQINIT never comes true).
                 */
@@ -1667,7 +1804,7 @@ export seq_isr:
                test    DFCNTRL, DIRECTION jz interrupt_return;
                and     DFCNTRL, ~SCSIEN;
 snapshot_wait_data_valid:
-               test    SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid;
+               test    SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz interrupt_return;
                test    SSTAT1, REQINIT jz snapshot_wait_data_valid;
 snapshot_data_valid:
                or      DFCNTRL, SCSIEN;
@@ -1834,7 +1971,6 @@ pkt_saveptrs_check_status:
        dec     SCB_FIFO_USE_COUNT;
        test    SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
        mvi     DFFSXFRCTL, CLRCHN ret;
-END_CRITICAL;
 
 /*
  * LAST_SEG_DONE status has been seen in the current FIFO.
@@ -1843,7 +1979,6 @@ END_CRITICAL;
  * Check for overrun and see if we can complete this command.
  */
 pkt_last_seg_done:
-BEGIN_CRITICAL;
        /*
         * Mark transfer as completed.
         */
index 4e8f00df978dab2ad226e1566f118b7108165081..db8f5ce99ee3f815a018a1264bb3c50299a7ce99 100644 (file)
@@ -37,9 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#202 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#247 $
  */
 
 #ifdef __linux__
@@ -332,6 +330,14 @@ ahd_restart(struct ahd_softc *ahd)
        ahd_outb(ahd, SCSISEQ1,
                 ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));
        ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+
+       /*
+        * Clear any pending sequencer interrupt.  It is no
+        * longer relevant since we're resetting the Program
+        * Counter.
+        */
+       ahd_outb(ahd, CLRINT, CLRSEQINT);
+
        ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET);
        ahd_unpause(ahd);
 }
@@ -373,13 +379,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
        saved_modes = ahd_save_modes(ahd);
 
        /*
-        * Complete any SCBs that just finished being
-        * DMA'ed into the qoutfifo.
-        */
-       ahd_run_qoutfifo(ahd);
-
-       /*
-        * Flush the good status FIFO for compelted packetized commands.
+        * Flush the good status FIFO for completed packetized commands.
         */
        ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
        saved_scbptr = ahd_get_scbptr(ahd);
@@ -387,8 +387,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
                u_int fifo_mode;
                u_int i;
                
-               scbid = (ahd_inb(ahd, GSFIFO+1) << 8)
-                     | ahd_inb(ahd, GSFIFO);
+               scbid = ahd_inw(ahd, GSFIFO);
                scb = ahd_lookup_scb(ahd, scbid);
                if (scb == NULL) {
                        printf("%s: Warning - GSFIFO SCB %d invalid\n",
@@ -401,22 +400,33 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
                 * the host before completing the  command.
                 */
                fifo_mode = 0;
+rescan_fifos:
                for (i = 0; i < 2; i++) {
                        /* Toggle to the other mode. */
                        fifo_mode ^= 1;
                        ahd_set_modes(ahd, fifo_mode, fifo_mode);
+
                        if (ahd_scb_active_in_fifo(ahd, scb) == 0)
                                continue;
 
                        ahd_run_data_fifo(ahd, scb);
 
                        /*
-                        * Clearing this transaction in this FIFO may
-                        * cause a CFG4DATA for this same transaction
-                        * to assert in the other FIFO.  Make sure we
-                        * loop one more time and check the other FIFO.
+                        * Running this FIFO may cause a CFG4DATA for
+                        * this same transaction to assert in the other
+                        * FIFO or a new snapshot SAVEPTRS interrupt
+                        * in this FIFO.  Even running a FIFO may not
+                        * clear the transaction if we are still waiting
+                        * for data to drain to the host. We must loop
+                        * until the transaction is not active in either
+                        * FIFO just to be sure.  Reset our loop counter
+                        * so we will visit both FIFOs again before
+                        * declaring this transaction finished.  We
+                        * also delay a bit so that status has a chance
+                        * to change before we look at this FIFO again.
                         */
-                       i = 0;
+                       ahd_delay(200);
+                       goto rescan_fifos;
                }
                ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
                ahd_set_scbptr(ahd, scbid);
@@ -429,19 +439,28 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
                        /*
                         * The transfer completed with a residual.
                         * Place this SCB on the complete DMA list
-                        * so that we Update our in-core copy of the
+                        * so that we update our in-core copy of the
                         * SCB before completing the command.
                         */
                        ahd_outb(ahd, SCB_SCSI_STATUS, 0);
                        ahd_outb(ahd, SCB_SGPTR,
                                 ahd_inb_scbram(ahd, SCB_SGPTR)
                                 | SG_STATUS_VALID);
-                       ahd_outw(ahd, SCB_TAG, SCB_GET_TAG(scb));
+                       ahd_outw(ahd, SCB_TAG, scbid);
+                       ahd_outw(ahd, SCB_NEXT_COMPLETE, SCB_LIST_NULL);
                        comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
-                       ahd_outw(ahd, SCB_NEXT_COMPLETE, comp_head);
-                       if (SCBID_IS_NULL(comp_head))
-                               ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD,
-                                        SCB_GET_TAG(scb));
+                       if (SCBID_IS_NULL(comp_head)) {
+                               ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, scbid);
+                               ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid);
+                       } else {
+                               u_int tail;
+
+                               tail = ahd_inw(ahd, COMPLETE_DMA_SCB_TAIL);
+                               ahd_set_scbptr(ahd, tail);
+                               ahd_outw(ahd, SCB_NEXT_COMPLETE, scbid);
+                               ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid);
+                               ahd_set_scbptr(ahd, scbid);
+                       }
                } else
                        ahd_complete_scb(ahd, scb);
        }
@@ -465,9 +484,22 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
                        break;
                ahd_delay(200);
        }
-       if ((ccscbctl & CCSCBDIR) != 0)
+       /*
+        * We leave the sequencer to cleanup in the case of DMA's to
+        * update the qoutfifo.  In all other cases (DMA's to the
+        * chip or a push of an SCB from the COMPLETE_DMA_SCB list),
+        * we disable the DMA engine so that the sequencer will not
+        * attempt to handle the DMA completion.
+        */
+       if ((ccscbctl & CCSCBDIR) != 0 || (ccscbctl & ARRDONE) != 0)
                ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN));
 
+       /*
+        * Complete any SCBs that just finished
+        * being DMA'ed into the qoutfifo.
+        */
+       ahd_run_qoutfifo(ahd);
+
        saved_scbptr = ahd_get_scbptr(ahd);
        /*
         * Manually update/complete any completed SCBs that are waiting to be
@@ -494,6 +526,24 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd)
                scbid = next_scbid;
        }
        ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL);
+       ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL);
+
+       scbid = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD);
+       while (!SCBID_IS_NULL(scbid)) {
+
+               ahd_set_scbptr(ahd, scbid);
+               next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+               scb = ahd_lookup_scb(ahd, scbid);
+               if (scb == NULL) {
+                       printf("%s: Warning - Complete Qfrz SCB %d invalid\n",
+                              ahd_name(ahd), scbid);
+                       continue;
+               }
+
+               ahd_complete_scb(ahd, scb);
+               scbid = next_scbid;
+       }
+       ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL);
 
        scbid = ahd_inw(ahd, COMPLETE_SCB_HEAD);
        while (!SCBID_IS_NULL(scbid)) {
@@ -558,150 +608,146 @@ ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb)
 {
        u_int seqintsrc;
 
-       while (1) {
-               seqintsrc = ahd_inb(ahd, SEQINTSRC);
-               if ((seqintsrc & CFG4DATA) != 0) {
-                       uint32_t datacnt;
-                       uint32_t sgptr;
-
-                       /*
-                        * Clear full residual flag.
-                        */
-                       sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID;
-                       ahd_outb(ahd, SCB_SGPTR, sgptr);
+       seqintsrc = ahd_inb(ahd, SEQINTSRC);
+       if ((seqintsrc & CFG4DATA) != 0) {
+               uint32_t datacnt;
+               uint32_t sgptr;
 
-                       /*
-                        * Load datacnt and address.
-                        */
-                       datacnt = ahd_inl_scbram(ahd, SCB_DATACNT);
-                       if ((datacnt & AHD_DMA_LAST_SEG) != 0) {
-                               sgptr |= LAST_SEG;
-                               ahd_outb(ahd, SG_STATE, 0);
-                       } else
-                               ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
-                       ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR));
-                       ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK);
-                       ahd_outb(ahd, SG_CACHE_PRE, sgptr);
-                       ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN);
+               /*
+                * Clear full residual flag.
+                */
+               sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID;
+               ahd_outb(ahd, SCB_SGPTR, sgptr);
 
-                       /*
-                        * Initialize Residual Fields.
-                        */
-                       ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24);
-                       ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK);
+               /*
+                * Load datacnt and address.
+                */
+               datacnt = ahd_inl_scbram(ahd, SCB_DATACNT);
+               if ((datacnt & AHD_DMA_LAST_SEG) != 0) {
+                       sgptr |= LAST_SEG;
+                       ahd_outb(ahd, SG_STATE, 0);
+               } else
+                       ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
+               ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR));
+               ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK);
+               ahd_outb(ahd, SG_CACHE_PRE, sgptr);
+               ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN);
 
-                       /*
-                        * Mark the SCB as having a FIFO in use.
-                        */
-                       ahd_outb(ahd, SCB_FIFO_USE_COUNT,
-                                ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1);
+               /*
+                * Initialize Residual Fields.
+                */
+               ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24);
+               ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK);
 
-                       /*
-                        * Install a "fake" handler for this FIFO.
-                        */
-                       ahd_outw(ahd, LONGJMP_ADDR, 0);
+               /*
+                * Mark the SCB as having a FIFO in use.
+                */
+               ahd_outb(ahd, SCB_FIFO_USE_COUNT,
+                        ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1);
 
-                       /*
-                        * Notify the hardware that we have satisfied
-                        * this sequencer interrupt.
-                        */
-                       ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA);
-               } else if ((seqintsrc & SAVEPTRS) != 0) {
-                       uint32_t sgptr;
-                       uint32_t resid;
+               /*
+                * Install a "fake" handler for this FIFO.
+                */
+               ahd_outw(ahd, LONGJMP_ADDR, 0);
 
-                       if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) {
-                               /*
-                                * Snapshot Save Pointers.  Clear
-                                * the snapshot and continue.
-                                */
-                               ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
-                               continue;
-                       }
+               /*
+                * Notify the hardware that we have satisfied
+                * this sequencer interrupt.
+                */
+               ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA);
+       } else if ((seqintsrc & SAVEPTRS) != 0) {
+               uint32_t sgptr;
+               uint32_t resid;
 
+               if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) {
                        /*
-                        * Disable S/G fetch so the DMA engine
-                        * is available to future users.
+                        * Snapshot Save Pointers.  All that
+                        * is necessary to clear the snapshot
+                        * is a CLRCHN.
                         */
-                       if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)
-                               ahd_outb(ahd, CCSGCTL, 0);
-                       ahd_outb(ahd, SG_STATE, 0);
+                       goto clrchn;
+               }
 
-                       /*
-                        * Flush the data FIFO.  Strickly only
-                        * necessary for Rev A parts.
-                        */
-                       ahd_outb(ahd, DFCNTRL,
-                                ahd_inb(ahd, DFCNTRL) | FIFOFLUSH);
+               /*
+                * Disable S/G fetch so the DMA engine
+                * is available to future users.
+                */
+               if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)
+                       ahd_outb(ahd, CCSGCTL, 0);
+               ahd_outb(ahd, SG_STATE, 0);
 
-                       /*
-                        * Calculate residual.
-                        */
-                       sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
-                       resid = ahd_inl(ahd, SHCNT);
-                       resid |=
-                           ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24;
-                       ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid);
-                       if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) {
-                               /*
-                                * Must back up to the correct S/G element.
-                                * Typically this just means resetting our
-                                * low byte to the offset in the SG_CACHE,
-                                * but if we wrapped, we have to correct
-                                * the other bytes of the sgptr too.
-                                */
-                               if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0
-                                && (sgptr & 0x80) == 0)
-                                       sgptr -= 0x100;
-                               sgptr &= ~0xFF;
-                               sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW)
-                                      & SG_ADDR_MASK;
-                               ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
-                               ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0);
-                       } else if ((resid & AHD_SG_LEN_MASK) == 0) {
-                               ahd_outb(ahd, SCB_RESIDUAL_SGPTR,
-                                        sgptr | SG_LIST_NULL);
-                       }
-                       /*
-                        * Save Pointers.
-                        */
-                       ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR));
-                       ahd_outl(ahd, SCB_DATACNT, resid);
-                       ahd_outl(ahd, SCB_SGPTR, sgptr);
-                       ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS);
-                       ahd_outb(ahd, SEQIMODE,
-                                ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS);
-                       /*
-                        * If the data is to the SCSI bus, we are
-                        * done, otherwise wait for FIFOEMP.
-                        */
-                       if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0)
-                               break;
-               } else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) {
-                       uint32_t sgptr;
-                       uint64_t data_addr;
-                       uint32_t data_len;
-                       u_int    dfcntrl;
+               /*
+                * Flush the data FIFO.  Strickly only
+                * necessary for Rev A parts.
+                */
+               ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) | FIFOFLUSH);
 
+               /*
+                * Calculate residual.
+                */
+               sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
+               resid = ahd_inl(ahd, SHCNT);
+               resid |= ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24;
+               ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid);
+               if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) {
                        /*
-                        * Disable S/G fetch so the DMA engine
-                        * is available to future users.
+                        * Must back up to the correct S/G element.
+                        * Typically this just means resetting our
+                        * low byte to the offset in the SG_CACHE,
+                        * but if we wrapped, we have to correct
+                        * the other bytes of the sgptr too.
                         */
-                       if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) {
-                               ahd_outb(ahd, CCSGCTL, 0);
-                               ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
-                       }
+                       if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0
+                        && (sgptr & 0x80) == 0)
+                               sgptr -= 0x100;
+                       sgptr &= ~0xFF;
+                       sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW)
+                              & SG_ADDR_MASK;
+                       ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
+                       ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0);
+               } else if ((resid & AHD_SG_LEN_MASK) == 0) {
+                       ahd_outb(ahd, SCB_RESIDUAL_SGPTR,
+                                sgptr | SG_LIST_NULL);
+               }
+               /*
+                * Save Pointers.
+                */
+               ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR));
+               ahd_outl(ahd, SCB_DATACNT, resid);
+               ahd_outl(ahd, SCB_SGPTR, sgptr);
+               ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS);
+               ahd_outb(ahd, SEQIMODE,
+                        ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS);
+               /*
+                * If the data is to the SCSI bus, we are
+                * done, otherwise wait for FIFOEMP.
+                */
+               if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0)
+                       goto clrchn;
+       } else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) {
+               uint32_t sgptr;
+               uint64_t data_addr;
+               uint32_t data_len;
+               u_int    dfcntrl;
 
-                       /*
-                        * Wait for the DMA engine to notice that the
-                        * host transfer is enabled and that there is
-                        * space in the S/G FIFO for new segments before
-                        * loading more segments.
-                        */
-                       if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) == 0)
-                               continue;
-                       if ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) == 0)
-                               continue;
+               /*
+                * Disable S/G fetch so the DMA engine
+                * is available to future users.  We won't
+                * be using the DMA engine to load segments.
+                */
+               if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) {
+                       ahd_outb(ahd, CCSGCTL, 0);
+                       ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
+               }
+
+               /*
+                * Wait for the DMA engine to notice that the
+                * host transfer is enabled and that there is
+                * space in the S/G FIFO for new segments before
+                * loading more segments.
+                */
+               if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) != 0
+                && (ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) {
 
                        /*
                         * Determine the offset of the next S/G
@@ -748,7 +794,7 @@ ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb)
                         * Advertise the segment to the hardware.
                         */
                        dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN;
-                       if ((ahd->features & AHD_NEW_DFCNTRL_OPTS)!=0) {
+                       if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {
                                /*
                                 * Use SCSIENWRDIS so that SCSIEN
                                 * is never modified by this
@@ -757,35 +803,44 @@ ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb)
                                dfcntrl |= SCSIENWRDIS;
                        }
                        ahd_outb(ahd, DFCNTRL, dfcntrl);
-               } else if ((ahd_inb(ahd, SG_CACHE_SHADOW)
-                        & LAST_SEG_DONE) != 0) {
-
-                       /*
-                        * Transfer completed to the end of SG list
-                        * and has flushed to the host.
-                        */
-                       ahd_outb(ahd, SCB_SGPTR,
-                                ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL);
-                       break;
-               } else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) {
-                       break;
                }
-               ahd_delay(200);
+       } else if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG_DONE) != 0) {
+
+               /*
+                * Transfer completed to the end of SG list
+                * and has flushed to the host.
+                */
+               ahd_outb(ahd, SCB_SGPTR,
+                        ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL);
+               goto clrchn;
+       } else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) {
+clrchn:
+               /*
+                * Clear any handler for this FIFO, decrement
+                * the FIFO use count for the SCB, and release
+                * the FIFO.
+                */
+               ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
+               ahd_outb(ahd, SCB_FIFO_USE_COUNT,
+                        ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1);
+               ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
        }
-       /*
-        * Clear any handler for this FIFO, decrement
-        * the FIFO use count for the SCB, and release
-        * the FIFO.
-        */
-       ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
-       ahd_outb(ahd, SCB_FIFO_USE_COUNT,
-                ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1);
-       ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
 }
 
+/*
+ * Look for entries in the QoutFIFO that have completed.
+ * The valid_tag completion field indicates the validity
+ * of the entry - the valid value toggles each time through
+ * the queue. We use the sg_status field in the completion
+ * entry to avoid referencing the hscb if the completion
+ * occurred with no errors and no residual.  sg_status is
+ * a copy of the first byte (little endian) of the sgptr
+ * hscb field.
+ */
 void
 ahd_run_qoutfifo(struct ahd_softc *ahd)
 {
+       struct ahd_completion *completion;
        struct scb *scb;
        u_int  scb_index;
 
@@ -793,11 +848,13 @@ ahd_run_qoutfifo(struct ahd_softc *ahd)
                panic("ahd_run_qoutfifo recursion");
        ahd->flags |= AHD_RUNNING_QOUTFIFO;
        ahd_sync_qoutfifo(ahd, BUS_DMASYNC_POSTREAD);
-       while ((ahd->qoutfifo[ahd->qoutfifonext]
-            & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) {
+       for (;;) {
+               completion = &ahd->qoutfifo[ahd->qoutfifonext];
 
-               scb_index = ahd_le16toh(ahd->qoutfifo[ahd->qoutfifonext]
-                                     & ~QOUTFIFO_ENTRY_VALID_LE);
+               if (completion->valid_tag != ahd->qoutfifonext_valid_tag)
+                       break;
+
+               scb_index = ahd_le16toh(completion->tag);
                scb = ahd_lookup_scb(ahd, scb_index);
                if (scb == NULL) {
                        printf("%s: WARNING no command for scb %d "
@@ -805,12 +862,15 @@ ahd_run_qoutfifo(struct ahd_softc *ahd)
                               ahd_name(ahd), scb_index,
                               ahd->qoutfifonext);
                        ahd_dump_card_state(ahd);
-               } else
-                       ahd_complete_scb(ahd, scb);
+               } else if ((completion->sg_status & SG_STATUS_VALID) != 0) {
+                       ahd_handle_scb_status(ahd, scb);
+               } else {
+                       ahd_done(ahd, scb);
+               }
 
                ahd->qoutfifonext = (ahd->qoutfifonext+1) & (AHD_QOUT_SIZE-1);
                if (ahd->qoutfifonext == 0)
-                       ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID_LE;
+                       ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID;
        }
        ahd->flags &= ~AHD_RUNNING_QOUTFIFO;
 }
@@ -876,26 +936,6 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
                       ahd_name(ahd), seqintcode);
 #endif
        switch (seqintcode) {
-       case BAD_SCB_STATUS:
-       {
-               struct  scb *scb;
-               u_int   scbid;
-               int     cmds_pending;
-
-               scbid = ahd_get_scbptr(ahd);
-               scb = ahd_lookup_scb(ahd, scbid);
-               if (scb != NULL) {
-                       ahd_complete_scb(ahd, scb);
-               } else {
-                       printf("%s: WARNING no command for scb %d "
-                              "(bad status)\n", ahd_name(ahd), scbid);
-                       ahd_dump_card_state(ahd);
-               }
-               cmds_pending = ahd_inw(ahd, CMDS_PENDING);
-               if (cmds_pending > 0)
-                       ahd_outw(ahd, CMDS_PENDING, cmds_pending - 1);
-               break;
-       }
        case ENTERING_NONPACK:
        {
                struct  scb *scb;
@@ -1060,7 +1100,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
                        ahd_outb(ahd, SAVED_LUN, 0);
                        ahd_outb(ahd, SEQ_FLAGS, 0);
                        ahd_assert_atn(ahd);
-                       scb->flags &= ~(SCB_PACKETIZED);
+                       scb->flags &= ~SCB_PACKETIZED;
                        scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT;
                        ahd_freeze_devq(ahd, scb);
                        ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
@@ -1503,9 +1543,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
         && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
                scb = NULL;
 
-       /* Make sure the sequencer is in a safe location. */
-       ahd_clear_critical_section(ahd);
-
        if ((status0 & IOERR) != 0) {
                u_int now_lvd;
 
@@ -1521,26 +1558,35 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                ahd_setup_iocell_workaround(ahd);
                ahd_unpause(ahd);
        } else if ((status0 & OVERRUN) != 0) {
+
                printf("%s: SCSI offset overrun detected.  Resetting bus.\n",
                       ahd_name(ahd));
                ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
        } else if ((status & SCSIRSTI) != 0) {
+
                printf("%s: Someone reset channel A\n", ahd_name(ahd));
                ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
        } else if ((status & SCSIPERR) != 0) {
+
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                ahd_handle_transmission_error(ahd);
        } else if (lqostat0 != 0) {
+
                printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
                ahd_outb(ahd, CLRLQOINT0, lqostat0);
-               if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
+               if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
                        ahd_outb(ahd, CLRLQOINT1, 0);
-               }
        } else if ((status & SELTO) != 0) {
                u_int  scbid;
 
                /* Stop the selection */
                ahd_outb(ahd, SCSISEQ0, 0);
 
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                /* No more pending messages */
                ahd_clear_msg_state(ahd);
 
@@ -1573,24 +1619,27 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                                       scbid);
                        }
 #endif
-                       /*
-                        * Force a renegotiation with this target just in
-                        * case the cable was pulled and will later be
-                        * re-attached.  The target may forget its negotiation
-                        * settings with us should it attempt to reselect
-                        * during the interruption.  The target will not issue
-                        * a unit attention in this case, so we must always
-                        * renegotiate.
-                        */
                        ahd_scb_devinfo(ahd, &devinfo, scb);
-                       ahd_force_renegotiation(ahd, &devinfo);
                        ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT);
                        ahd_freeze_devq(ahd, scb);
+
+                       /*
+                        * Cancel any pending transactions on the device
+                        * now that it seems to be missing.  This will
+                        * also revert us to async/narrow transfers until
+                        * we can renegotiate with the device.
+                        */
+                       ahd_handle_devreset(ahd, &devinfo,
+                                           CAM_LUN_WILDCARD,
+                                           CAM_SEL_TIMEOUT,
+                                           "Selection Timeout",
+                                           /*verbose_level*/1);
                }
                ahd_outb(ahd, CLRINT, CLRSCSIINT);
                ahd_iocell_first_selection(ahd);
                ahd_unpause(ahd);
        } else if ((status0 & (SELDI|SELDO)) != 0) {
+
                ahd_iocell_first_selection(ahd);
                ahd_unpause(ahd);
        } else if (status3 != 0) {
@@ -1598,6 +1647,10 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                       ahd_name(ahd), status3);
                ahd_outb(ahd, CLRSINT3, status3);
        } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
+
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                ahd_handle_lqiphase_error(ahd, lqistat1);
        } else if ((lqistat1 & LQICRCI_NLQ) != 0) {
                /*
@@ -1622,6 +1675,9 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                 */
                ahd_outb(ahd, SCSISEQ0, 0);
 
+               /* Make sure the sequencer is in a safe location. */
+               ahd_clear_critical_section(ahd);
+
                /*
                 * Determine what we were up to at the time of
                 * the busfree.
@@ -1659,7 +1715,16 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
                        clear_fifo = 0;
                        packetized =  (lqostat1 & LQOBUSFREE) != 0;
                        if (!packetized
-                        && ahd_inb(ahd, LASTPHASE) == P_BUSFREE)
+                        && ahd_inb(ahd, LASTPHASE) == P_BUSFREE
+                        && (ahd_inb(ahd, SSTAT0) & SELDI) == 0
+                        && ((ahd_inb(ahd, SSTAT0) & SELDO) == 0
+                         || (ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0))
+                               /*
+                                * Assume packetized if we are not
+                                * on the bus in a non-packetized
+                                * capacity and any pending selection
+                                * was a packetized selection.
+                                */
                                packetized = 1;
                        break;
                }
@@ -2310,8 +2375,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
                       "PRGMCNT == 0x%x\n",
                       ahd_lookup_phase_entry(lastphase)->phasemsg,
                       aborted,
-                      ahd_inb(ahd, PRGMCNT)
-                       | (ahd_inb(ahd, PRGMCNT+1) << 8));
+                      ahd_inw(ahd, PRGMCNT));
                ahd_dump_card_state(ahd);
        }
        /* Always restart the sequencer. */
@@ -2474,8 +2538,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd)
                u_int   i;
 
                ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-               seqaddr = ahd_inb(ahd, CURADDR)
-                       | (ahd_inb(ahd, CURADDR+1) << 8);
+               seqaddr = ahd_inw(ahd, CURADDR);
 
                cs = ahd->critical_sections;
                for (i = 0; i < ahd->num_critical_sections; i++, cs++) {
@@ -3196,14 +3259,25 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
                iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK;
 
                if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0
-                && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0) {
+                && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0
+                && (ppr_opts & MSG_EXT_PPR_IU_REQ) == 0) {
                        /*
                         * Slow down our CRC interval to be
-                        * compatible with devices that can't
-                        * handle a CRC at full speed.
+                        * compatible with non-packetized
+                        * U160 devices that can't handle a
+                        * CRC at full speed.
                         */
                        con_opts |= ENSLOWCRC;
                }
+
+               if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) {
+                       /*
+                        * On H2A4, revert to a slower slewrate
+                        * on non-paced transfers.
+                        */
+                       iocell_opts[AHD_PRECOMP_SLEW_INDEX] &=
+                           ~AHD_SLEWRATE_MASK;
+               }
        }
 
        ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW);
@@ -3292,11 +3366,15 @@ ahd_update_pending_scbs(struct ahd_softc *ahd)
         * Force the sequencer to reinitialize the selection for
         * the command at the head of the execution queue if it
         * has already been setup.  The negotiation changes may
-        * effect whether we select-out with ATN.
+        * effect whether we select-out with ATN.  It is only
+        * safe to clear ENSELO when the bus is not free and no
+        * selection is in progres or completed.
         */
        saved_modes = ahd_save_modes(ahd);
        ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-       ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+       if ((ahd_inb(ahd, SCSISIGI) & BSYI) != 0
+        && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
+               ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
        saved_scbptr = ahd_get_scbptr(ahd);
        /* Ensure that the hscbs down on the card match the new information */
        for (scb_tag = 0; scb_tag < ahd->scb_data.maxhscbs; scb_tag++) {
@@ -4909,10 +4987,7 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
         * Determine initial values for data_addr and data_cnt
         * for resuming the data phase.
         */
-       sgptr = (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24)
-             | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16)
-             | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8)
-             | ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR);
+       sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
        sgptr &= SG_PTR_MASK;
 
        resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16)
@@ -4930,10 +5005,7 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
                dataptr = ahd_le64toh(sg->addr)
                        + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK)
                        - resid;
-               ahd_outb(ahd, HADDR + 7, dataptr >> 56);
-               ahd_outb(ahd, HADDR + 6, dataptr >> 48);
-               ahd_outb(ahd, HADDR + 5, dataptr >> 40);
-               ahd_outb(ahd, HADDR + 4, dataptr >> 32);
+               ahd_outl(ahd, HADDR + 4, dataptr >> 32);
        } else {
                struct   ahd_dma_seg *sg;
 
@@ -4948,10 +5020,7 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
                ahd_outb(ahd, HADDR + 4,
                         (ahd_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24);
        }
-       ahd_outb(ahd, HADDR + 3, dataptr >> 24);
-       ahd_outb(ahd, HADDR + 2, dataptr >> 16);
-       ahd_outb(ahd, HADDR + 1, dataptr >> 8);
-       ahd_outb(ahd, HADDR, dataptr);
+       ahd_outl(ahd, HADDR, dataptr);
        ahd_outb(ahd, HCNT + 2, resid >> 16);
        ahd_outb(ahd, HCNT + 1, resid >> 8);
        ahd_outb(ahd, HCNT, resid);
@@ -5011,13 +5080,14 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
        ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
                      AHD_TRANS_CUR, /*paused*/TRUE);
        ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0,
-                        /*ppr_options*/0, AHD_TRANS_CUR, /*paused*/TRUE);
+                        /*ppr_options*/0, AHD_TRANS_CUR,
+                        /*paused*/TRUE);
        
-       ahd_send_async(ahd, devinfo->channel, devinfo->target,
-                      lun, AC_SENT_BDR, NULL);
+       if (status != CAM_SEL_TIMEOUT)
+               ahd_send_async(ahd, devinfo->channel, devinfo->target,
+                              CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
 
-       if (message != NULL
-        && (verbose_level <= bootverbose))
+       if (message != NULL && bootverbose)
                printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
                       message, devinfo->channel, devinfo->target, found);
 }
@@ -5203,13 +5273,13 @@ ahd_free(struct ahd_softc *ahd)
                /* FALLTHROUGH */
        case 4:
                ahd_dmamap_unload(ahd, ahd->shared_data_dmat,
-                                 ahd->shared_data_dmamap);
+                                 ahd->shared_data_map.dmamap);
                /* FALLTHROUGH */
        case 3:
                ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo,
-                               ahd->shared_data_dmamap);
+                               ahd->shared_data_map.dmamap);
                ahd_dmamap_destroy(ahd, ahd->shared_data_dmat,
-                                  ahd->shared_data_dmamap);
+                                  ahd->shared_data_map.dmamap);
                /* FALLTHROUGH */
        case 2:
                ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat);
@@ -5975,16 +6045,13 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
        newcount = MIN(scb_data->sense_left, scb_data->scbs_left);
        newcount = MIN(newcount, scb_data->sgs_left);
        newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
-       scb_data->sense_left -= newcount;
-       scb_data->scbs_left -= newcount;
-       scb_data->sgs_left -= newcount;
        for (i = 0; i < newcount; i++) {
-               u_int col_tag;
-
                struct scb_platform_data *pdata;
+               u_int col_tag;
 #ifndef __linux__
                int error;
 #endif
+
                next_scb = (struct scb *)malloc(sizeof(*next_scb),
                                                M_DEVBUF, M_NOWAIT);
                if (next_scb == NULL)
@@ -6041,6 +6108,9 @@ ahd_alloc_scbs(struct ahd_softc *ahd)
                sense_data += AHD_SENSE_BUFSIZE;
                sense_busaddr += AHD_SENSE_BUFSIZE;
                scb_data->numscbs++;
+               scb_data->sense_left--;
+               scb_data->scbs_left--;
+               scb_data->sgs_left--;
        }
 }
 
@@ -6088,7 +6158,6 @@ static const char *termstat_strings[] = {
 int
 ahd_init(struct ahd_softc *ahd)
 {
-       uint8_t         *base_vaddr;
        uint8_t         *next_vaddr;
        dma_addr_t       next_baddr;
        size_t           driver_data_size;
@@ -6156,7 +6225,7 @@ ahd_init(struct ahd_softc *ahd)
         * for the target mode role, we must additionally provide space for
         * the incoming target command fifo.
         */
-       driver_data_size = AHD_SCB_MAX * sizeof(uint16_t)
+       driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo)
                         + sizeof(struct hardware_scb);
        if ((ahd->features & AHD_TARGETMODE) != 0)
                driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd);
@@ -6178,20 +6247,23 @@ ahd_init(struct ahd_softc *ahd)
 
        /* Allocation of driver data */
        if (ahd_dmamem_alloc(ahd, ahd->shared_data_dmat,
-                            (void **)&base_vaddr,
-                            BUS_DMA_NOWAIT, &ahd->shared_data_dmamap) != 0) {
+                            (void **)&ahd->shared_data_map.vaddr,
+                            BUS_DMA_NOWAIT,
+                            &ahd->shared_data_map.dmamap) != 0) {
                return (ENOMEM);
        }
 
        ahd->init_level++;
 
        /* And permanently map it in */
-       ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
-                       base_vaddr, driver_data_size, ahd_dmamap_cb,
-                       &ahd->shared_data_busaddr, /*flags*/0);
-       ahd->qoutfifo = (uint16_t *)base_vaddr;
+       ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+                       ahd->shared_data_map.vaddr, driver_data_size,
+                       ahd_dmamap_cb, &ahd->shared_data_map.physaddr,
+                       /*flags*/0);
+       ahd->qoutfifo = (struct ahd_completion *)ahd->shared_data_map.vaddr;
        next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE];
-       next_baddr = ahd->shared_data_busaddr + AHD_QOUT_SIZE*sizeof(uint16_t);
+       next_baddr = ahd->shared_data_map.physaddr
+                  + AHD_QOUT_SIZE*sizeof(struct ahd_completion);
        if ((ahd->features & AHD_TARGETMODE) != 0) {
                ahd->targetcmds = (struct target_cmd *)next_vaddr;
                next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd);
@@ -6212,6 +6284,7 @@ ahd_init(struct ahd_softc *ahd)
         * specially from the DMA safe memory chunk used for the QOUTFIFO.
         */
        ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr;
+       ahd->next_queued_hscb_map = &ahd->shared_data_map;
        ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr);
 
        ahd->init_level++;
@@ -6517,10 +6590,10 @@ ahd_chip_init(struct ahd_softc *ahd)
 
        /* All of our queues are empty */
        ahd->qoutfifonext = 0;
-       ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID_LE;
-       ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID >> 8);
+       ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID;
+       ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID);
        for (i = 0; i < AHD_QOUT_SIZE; i++)
-               ahd->qoutfifo[i] = 0;
+               ahd->qoutfifo[i].valid_tag = 0;
        ahd_sync_qoutfifo(ahd, BUS_DMASYNC_PREREAD);
 
        ahd->qinfifonext = 0;
@@ -6553,24 +6626,22 @@ ahd_chip_init(struct ahd_softc *ahd)
        ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL);
        ahd_outw(ahd, COMPLETE_SCB_DMAINPROG_HEAD, SCB_LIST_NULL);
        ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL);
+       ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL);
+       ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL);
 
        /*
         * The Freeze Count is 0.
         */
+       ahd->qfreeze_cnt = 0;
        ahd_outw(ahd, QFREEZE_COUNT, 0);
+       ahd_outw(ahd, KERNEL_QFREEZE_COUNT, 0);
 
        /*
         * Tell the sequencer where it can find our arrays in memory.
         */
-       busaddr = ahd->shared_data_busaddr;
-       ahd_outb(ahd, SHARED_DATA_ADDR, busaddr & 0xFF);
-       ahd_outb(ahd, SHARED_DATA_ADDR + 1, (busaddr >> 8) & 0xFF);
-       ahd_outb(ahd, SHARED_DATA_ADDR + 2, (busaddr >> 16) & 0xFF);
-       ahd_outb(ahd, SHARED_DATA_ADDR + 3, (busaddr >> 24) & 0xFF);
-       ahd_outb(ahd, QOUTFIFO_NEXT_ADDR, busaddr & 0xFF);
-       ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 1, (busaddr >> 8) & 0xFF);
-       ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 2, (busaddr >> 16) & 0xFF);
-       ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 3, (busaddr >> 24) & 0xFF);
+       busaddr = ahd->shared_data_map.physaddr;
+       ahd_outl(ahd, SHARED_DATA_ADDR, busaddr);
+       ahd_outl(ahd, QOUTFIFO_NEXT_ADDR, busaddr);
 
        /*
         * Setup the allowed SCSI Sequences based on operational mode.
@@ -6619,10 +6690,7 @@ ahd_chip_init(struct ahd_softc *ahd)
         * Tell the sequencer which SCB will be the next one it receives.
         */
        busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+       ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr);
 
        /*
         * Default to coalescing disabled.
@@ -6926,43 +6994,34 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
 {
        u_int intstat;
        u_int maxloops;
-       u_int qfreeze_cnt;
 
        maxloops = 1000;
        ahd->flags |= AHD_ALL_INTERRUPTS;
        ahd_pause(ahd);
        /*
-        * Increment the QFreeze Count so that the sequencer
-        * will not start new selections.  We do this only
+        * Freeze the outgoing selections.  We do this only
         * until we are safely paused without further selections
         * pending.
         */
-       ahd_outw(ahd, QFREEZE_COUNT, ahd_inw(ahd, QFREEZE_COUNT) + 1);
+       ahd->qfreeze_cnt--;
+       ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
        ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN);
        do {
-               struct scb *waiting_scb;
 
                ahd_unpause(ahd);
+               /*
+                * Give the sequencer some time to service
+                * any active selections.
+                */
+               ahd_delay(500);
+
                ahd_intr(ahd);
                ahd_pause(ahd);
-               ahd_clear_critical_section(ahd);
                intstat = ahd_inb(ahd, INTSTAT);
-               ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
-               if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
-                       ahd_outb(ahd, SCSISEQ0,
-                                ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
-               /*
-                * In the non-packetized case, the sequencer (for Rev A),
-                * relies on ENSELO remaining set after SELDO.  The hardware
-                * auto-clears ENSELO in the packetized case.
-                */
-               waiting_scb = ahd_lookup_scb(ahd,
-                                            ahd_inw(ahd, WAITING_TID_HEAD));
-               if (waiting_scb != NULL
-                && (waiting_scb->flags & SCB_PACKETIZED) == 0
-                && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)
-                       ahd_outb(ahd, SCSISEQ0,
-                                ahd_inb(ahd, SCSISEQ0) | ENSELO);
+               if ((intstat & INT_PEND) == 0) {
+                       ahd_clear_critical_section(ahd);
+                       intstat = ahd_inb(ahd, INTSTAT);
+               }
        } while (--maxloops
              && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
              && ((intstat & INT_PEND) != 0
@@ -6973,17 +7032,8 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
                printf("Infinite interrupt loop, INTSTAT = %x",
                      ahd_inb(ahd, INTSTAT));
        }
-       qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
-       if (qfreeze_cnt == 0) {
-               printf("%s: ahd_pause_and_flushwork with 0 qfreeze count!\n",
-                      ahd_name(ahd));
-       } else {
-               qfreeze_cnt--;
-       }
-       ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
-       if (qfreeze_cnt == 0)
-               ahd_outb(ahd, SEQ_FLAGS2,
-                        ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
+       ahd->qfreeze_cnt++;
+       ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
 
        ahd_flush_qoutfifo(ahd);
 
@@ -7155,10 +7205,7 @@ ahd_qinfifo_requeue(struct ahd_softc *ahd, struct scb *prev_scb,
                uint32_t busaddr;
 
                busaddr = ahd_le32toh(scb->hscb->hscb_busaddr);
-               ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
-               ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
-               ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
-               ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+               ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr);
        } else {
                prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
                ahd_sync_scb(ahd, prev_scb, 
@@ -7265,10 +7312,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
         */
        ahd->qinfifonext = qinstart;
        busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
-       ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+       ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr);
 
        while (qinpos != qintail) {
                scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]);
@@ -7330,6 +7374,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
         * appropriate, traverse the SCBs of each "their id"
         * looking for matches.
         */
+       ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
        savedscbptr = ahd_get_scbptr(ahd);
        tid_next = ahd_inw(ahd, WAITING_TID_HEAD);
        tid_prev = SCB_LIST_NULL;
@@ -7399,7 +7444,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
        u_int   prev;
        int     found;
 
-       AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+       AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
        found = 0;
        prev = SCB_LIST_NULL;
        next = *list_head;
@@ -7466,7 +7511,7 @@ static void
 ahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev,
                    u_int tid_cur, u_int tid_next)
 {
-       AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+       AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
 
        if (SCBID_IS_NULL(tid_cur)) {
 
@@ -7506,7 +7551,7 @@ ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
 {
        u_int tail_offset;
 
-       AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+       AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
        if (!SCBID_IS_NULL(prev)) {
                ahd_set_scbptr(ahd, prev);
                ahd_outw(ahd, SCB_NEXT, next);
@@ -7739,7 +7784,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
         */
        ahd_clear_msg_state(ahd);
        ahd_outb(ahd, SIMODE1,
-                ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE));
+                ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST));
 
        if (initiate_reset)
                ahd_reset_current_bus(ahd);
@@ -7910,30 +7955,35 @@ ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
 void
 ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
 {
-       struct hardware_scb *hscb;
-       u_int  qfreeze_cnt;
+       struct  hardware_scb *hscb;
+       int     paused;
 
        /*
         * The sequencer freezes its select-out queue
         * anytime a SCSI status error occurs.  We must
-        * handle the error and decrement the QFREEZE count
-        * to allow the sequencer to continue.
+        * handle the error and increment our qfreeze count
+        * to allow the sequencer to continue.  We don't
+        * bother clearing critical sections here since all
+        * operations are on data structures that the sequencer
+        * is not touching once the queue is frozen.
         */
        hscb = scb->hscb; 
 
+       if (ahd_is_paused(ahd)) {
+               paused = 1;
+       } else {
+               paused = 0;
+               ahd_pause(ahd);
+       }
+
        /* Freeze the queue until the client sees the error. */
        ahd_freeze_devq(ahd, scb);
        ahd_freeze_scb(scb);
-       qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
-       if (qfreeze_cnt == 0) {
-               printf("%s: Bad status with 0 qfreeze count!\n", ahd_name(ahd));
-       } else {
-               qfreeze_cnt--;
-               ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
-       }
-       if (qfreeze_cnt == 0)
-               ahd_outb(ahd, SEQ_FLAGS2,
-                        ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
+       ahd->qfreeze_cnt++;
+       ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt);
+
+       if (paused == 0)
+               ahd_unpause(ahd);
 
        /* Don't want to clobber the original sense code */
        if ((scb->flags & SCB_SENSE) != 0) {
@@ -8317,8 +8367,7 @@ ahd_dumpseq(struct ahd_softc* ahd)
        max_prog = 2048;
 
        ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
-       ahd_outb(ahd, PRGMCNT, 0);
-       ahd_outb(ahd, PRGMCNT+1, 0);
+       ahd_outw(ahd, PRGMCNT, 0);
        for (i = 0; i < max_prog; i++) {
                uint8_t ins_bytes[4];
 
@@ -8347,13 +8396,14 @@ ahd_loadseq(struct ahd_softc *ahd)
        u_int   sg_prefetch_cnt_limit;
        u_int   sg_prefetch_align;
        u_int   sg_size;
+       u_int   cacheline_mask;
        uint8_t download_consts[DOWNLOAD_CONST_COUNT];
 
        if (bootverbose)
                printf("%s: Downloading Sequencer Program...",
                       ahd_name(ahd));
 
-#if DOWNLOAD_CONST_COUNT != 7
+#if DOWNLOAD_CONST_COUNT != 8
 #error "Download Const Mismatch"
 #endif
        /*
@@ -8389,6 +8439,9 @@ ahd_loadseq(struct ahd_softc *ahd)
        /* Round down to the nearest power of 2. */
        while (powerof2(sg_prefetch_align) == 0)
                sg_prefetch_align--;
+
+       cacheline_mask = sg_prefetch_align - 1;
+
        /*
         * If the cacheline boundary is greater than half our prefetch RAM
         * we risk not being able to fetch even a single complete S/G
@@ -8429,12 +8482,12 @@ ahd_loadseq(struct ahd_softc *ahd)
        download_consts[PKT_OVERRUN_BUFOFFSET] =
                (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256;
        download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN;
+       download_consts[CACHELINE_MASK] = cacheline_mask;
        cur_patch = patches;
        downloaded = 0;
        skip_addr = 0;
        ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
-       ahd_outb(ahd, PRGMCNT, 0);
-       ahd_outb(ahd, PRGMCNT+1, 0);
+       ahd_outw(ahd, PRGMCNT, 0);
 
        for (i = 0; i < sizeof(seqprog)/4; i++) {
                if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) {
@@ -8727,7 +8780,7 @@ ahd_dump_card_state(struct ahd_softc *ahd)
        printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
               "%s: Dumping Card State at program address 0x%x Mode 0x%x\n",
               ahd_name(ahd), 
-              ahd_inb(ahd, CURADDR) | (ahd_inb(ahd, CURADDR+1) << 8),
+              ahd_inw(ahd, CURADDR),
               ahd_build_mode_state(ahd, ahd->saved_src_mode,
                                    ahd->saved_dst_mode));
        if (paused)
@@ -8843,6 +8896,15 @@ ahd_dump_card_state(struct ahd_softc *ahd)
                scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
        }
        printf("\n");
+       printf("Sequencer On QFreeze and Complete list: ");
+       scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD);
+       i = 0;
+       while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
+               ahd_set_scbptr(ahd, scb_index);
+               printf("%d ", scb_index);
+               scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+       }
+       printf("\n");
        ahd_set_scbptr(ahd, saved_scb_index);
        dffstat = ahd_inb(ahd, DFFSTAT);
        for (i = 0; i < 2; i++) {
@@ -9077,7 +9139,7 @@ ahd_wait_seeprom(struct ahd_softc *ahd)
 {
        int cnt;
 
-       cnt = 20;
+       cnt = 5000;
        while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt)
                ahd_delay(5);
 
@@ -9423,13 +9485,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
                        if ((ahd->features & AHD_MULTI_TID) != 0) {
                                u_int targid_mask;
 
-                               targid_mask = ahd_inb(ahd, TARGID)
-                                           | (ahd_inb(ahd, TARGID + 1) << 8);
-
+                               targid_mask = ahd_inw(ahd, TARGID);
                                targid_mask |= target_mask;
-                               ahd_outb(ahd, TARGID, targid_mask);
-                               ahd_outb(ahd, TARGID+1, (targid_mask >> 8));
-                               
+                               ahd_outw(ahd, TARGID, targid_mask);
                                ahd_update_scsiid(ahd, targid_mask);
                        } else {
                                u_int our_id;
@@ -9543,14 +9601,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
                                if (ahd->features & AHD_MULTI_TID) {
                                        u_int targid_mask;
 
-                                       targid_mask = ahd_inb(ahd, TARGID)
-                                                   | (ahd_inb(ahd, TARGID + 1)
-                                                      << 8);
-
+                                       targid_mask = ahd_inw(ahd, TARGID);
                                        targid_mask &= ~target_mask;
-                                       ahd_outb(ahd, TARGID, targid_mask);
-                                       ahd_outb(ahd, TARGID+1,
-                                                (targid_mask >> 8));
+                                       ahd_outw(ahd, TARGID, targid_mask);
                                        ahd_update_scsiid(ahd, targid_mask);
                                }
                        }
@@ -9651,7 +9704,7 @@ ahd_run_tqinfifo(struct ahd_softc *ahd, int paused)
 
                cmd->cmd_valid = 0;
                ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
-                               ahd->shared_data_dmamap,
+                               ahd->shared_data_map.dmamap,
                                ahd_targetcmd_offset(ahd, ahd->tqinfifonext),
                                sizeof(struct target_cmd),
                                BUS_DMASYNC_PREREAD);
index d80bc5161fb14c2ebb860218f6cc8e4f938c78cd..91c4f7f484b1271d37cf7b7334998aa30cff8344 100644 (file)
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#51 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#58 $
  *
  * $FreeBSD$
  */
@@ -522,12 +522,21 @@ do {                                                              \
 static __inline uint16_t
 ahd_inw(struct ahd_softc *ahd, u_int port)
 {
+       /*
+        * Read high byte first as some registers increment
+        * or have other side effects when the low byte is
+        * read.
+        */
        return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
 }
 
 static __inline void
 ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
 {
+       /*
+        * Write low byte first to accomodate registers
+        * such as PRGMCNT where the order maters.
+        */
        ahd_outb(ahd, port, value & 0xFF);
        ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
 }
@@ -684,7 +693,7 @@ ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
         * Razor #528
         */
        value = ahd_inb(ahd, offset);
-       if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
+       if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0)
                ahd_inb(ahd, MODE_PTR);
        return (value);
 }
@@ -727,7 +736,8 @@ ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
 static __inline void
 ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
 {
-       struct hardware_scb *q_hscb;
+       struct   hardware_scb *q_hscb;
+       struct   map_node *q_hscb_map;
        uint32_t saved_hscb_busaddr;
 
        /*
@@ -743,6 +753,7 @@ ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
         * locate the correct SCB by SCB_TAG.
         */
        q_hscb = ahd->next_queued_hscb;
+       q_hscb_map = ahd->next_queued_hscb_map;
        saved_hscb_busaddr = q_hscb->hscb_busaddr;
        memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
        q_hscb->hscb_busaddr = saved_hscb_busaddr;
@@ -750,7 +761,9 @@ ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
 
        /* Now swap HSCB pointers. */
        ahd->next_queued_hscb = scb->hscb;
+       ahd->next_queued_hscb_map = scb->hscb_map;
        scb->hscb = q_hscb;
+       scb->hscb_map = q_hscb_map;
 
        /* Now define the mapping from tag to SCB in the scbindex */
        ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
@@ -824,8 +837,9 @@ static __inline int ahd_intr(struct ahd_softc *ahd);
 static __inline void
 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
 {
-       ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
-                       /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op);
+       ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+                       /*offset*/0,
+                       /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op);
 }
 
 static __inline void
@@ -834,7 +848,7 @@ ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
 #ifdef AHD_TARGET_MODE
        if ((ahd->flags & AHD_TARGETROLE) != 0) {
                ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
-                               ahd->shared_data_dmamap,
+                               ahd->shared_data_map.dmamap,
                                ahd_targetcmd_offset(ahd, 0),
                                sizeof(struct target_cmd) * AHD_TMODE_CMDS,
                                op);
@@ -854,17 +868,17 @@ ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
        u_int retval;
 
        retval = 0;
-       ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
-                       /*offset*/ahd->qoutfifonext, /*len*/2,
-                       BUS_DMASYNC_POSTREAD);
-       if ((ahd->qoutfifo[ahd->qoutfifonext]
-            & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag)
+       ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap,
+                       /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo),
+                       /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD);
+       if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag
+         == ahd->qoutfifonext_valid_tag)
                retval |= AHD_RUN_QOUTFIFO;
 #ifdef AHD_TARGET_MODE
        if ((ahd->flags & AHD_TARGETROLE) != 0
         && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
                ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
-                               ahd->shared_data_dmamap,
+                               ahd->shared_data_map.dmamap,
                                ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
                                /*len*/sizeof(struct target_cmd),
                                BUS_DMASYNC_POSTREAD);
index 1c8f872e2dd41be16151067ebfb9553a6a6c6ab9..2567e29960bd1697565490d2840a3312f6414ab1 100644 (file)
@@ -1468,6 +1468,30 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
        if ((tstate->auto_negotiate & mask) != 0) {
                scb->flags |= SCB_AUTO_NEGOTIATE;
                scb->hscb->control |= MK_MESSAGE;
+               } else if (cmd->cmnd[0] == INQUIRY
+                       && (tinfo->curr.offset != 0
+                        || tinfo->curr.width != MSG_EXT_WDTR_BUS_8_BIT
+                        || tinfo->curr.ppr_options != 0)
+                       && (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)==0) {
+                       /*
+                        * The SCSI spec requires inquiry
+                        * commands to complete without
+                        * reporting unit attention conditions.
+                        * Because of this, an inquiry command
+                        * that occurs just after a device is
+                        * reset will result in a data phase
+                        * with mismatched negotiated rates.
+                        * The core already forces a renegotiation
+                        * for reset events that are visible to
+                        * our controller or that we initiate,
+                        * but a third party device reset or a
+                        * hot-plug insertion can still cause this
+                        * issue.  Therefore, we force a re-negotiation
+                        * for every inquiry command unless we
+                        * are async.
+                        */
+                       scb->flags |= SCB_NEGOTIATE;
+                       scb->hscb->control |= MK_MESSAGE;
        }
 
        if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
@@ -2058,6 +2082,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
        int    paused;
        int    wait;
        int    disconnected;
+       int    found;
        ahd_mode_state saved_modes;
        unsigned long flags;
 
@@ -2176,7 +2201,8 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
        last_phase = ahd_inb(ahd, LASTPHASE);
        saved_scbptr = ahd_get_scbptr(ahd);
        active_scbptr = saved_scbptr;
-       if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
+       if (disconnected && ((last_phase != P_BUSFREE) || 
+                            (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0)) {
                struct scb *bus_scb;
 
                bus_scb = ahd_lookup_scb(ahd, active_scbptr);
@@ -2194,28 +2220,41 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
         * bus or is in the disconnected state.
         */
        saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
-       if (last_phase != P_BUSFREE
-        && (SCB_GET_TAG(pending_scb) == active_scbptr
+       if (SCB_GET_TAG(pending_scb) == active_scbptr
             || (flag == SCB_DEVICE_RESET
-                && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd)))) {
+                && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd))) {
 
                /*
                 * We're active on the bus, so assert ATN
                 * and hope that the target responds.
                 */
                pending_scb = ahd_lookup_scb(ahd, active_scbptr);
-               pending_scb->flags |= SCB_RECOVERY_SCB|flag;
+               pending_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET;
                ahd_outb(ahd, MSG_OUT, HOST_MSG);
                ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
-               scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n");
+               scmd_printk(KERN_INFO, cmd, "BDR message in message buffer\n");
                wait = TRUE;
+       } else if (last_phase != P_BUSFREE
+                  && ahd_inb(ahd, SCSIPHASE) == 0) {
+               /*
+                * SCB is not identified, there
+                * is no pending REQ, and the sequencer
+                * has not seen a busfree.  Looks like
+                * a stuck connection waiting to
+                * go busfree.  Reset the bus.
+                */
+               found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
+                                         /*Initiate Reset*/TRUE);
+               printf("%s: Issued Channel %c Bus Reset. "
+                      "%d SCBs aborted\n", ahd_name(ahd),
+                      cmd->device->channel + 'A', found);
        } else if (disconnected) {
 
                /*
                 * Actually re-queue this SCB in an attempt
                 * to select the device before it reconnects.
                 */
-               pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
+               pending_scb->flags |= SCB_RECOVERY_SCB|flag;
                ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
                pending_scb->hscb->cdb_len = 0;
                pending_scb->hscb->task_attribute = 0;
@@ -2296,16 +2335,17 @@ done:
                timer.expires = jiffies + (5 * HZ);
                timer.function = ahd_linux_sem_timeout;
                add_timer(&timer);
-               printf("Recovery code sleeping\n");
+               printf("%s: Recovery code sleeping\n", ahd_name(ahd));
                down(&ahd->platform_data->eh_sem);
-               printf("Recovery code awake\n");
+               printf("%s: Recovery code awake\n", ahd_name(ahd));
                ret = del_timer_sync(&timer);
                if (ret == 0) {
-                       printf("Timer Expired\n");
+                       printf("%s: Timer Expired (active %d)\n",
+                              ahd_name(ahd), dev->active);
                        retval = FAILED;
                }
        }
-               ahd_unlock(ahd, &flags);
+       ahd_unlock(ahd, &flags);
        return (retval);
 }
 
index bc44222d6cc3b5bc0dedb6e9a012833333f706b7..cb74fccc81007130f602eb75dda433a5d890f113 100644 (file)
@@ -252,7 +252,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec)
 /***************************** SMP support ************************************/
 #include <linux/spinlock.h>
 
-#define AIC79XX_DRIVER_VERSION "1.3.11"
+#define AIC79XX_DRIVER_VERSION "3.0"
 
 /*************************** Device Data Structures ***************************/
 /*
index 2131db60018a3242592344d69b6b794233b041a1..196a6344b03703ec9b96182d747f20d5b50eafbb 100644 (file)
@@ -38,9 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#77 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#89 $
  */
 
 #ifdef __linux__
@@ -114,6 +112,13 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
                "Adaptec 29320ALP Ultra320 SCSI adapter",
                ahd_aic7901_setup
        },
+       /* aic7901A based controllers */
+       {
+               ID_AHA_29320LP,
+               ID_ALL_MASK,
+               "Adaptec 29320LP Ultra320 SCSI adapter",
+               ahd_aic7901A_setup
+       },
        /* aic7902 based controllers */ 
        {
                ID_AHA_29320,
@@ -127,12 +132,6 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
                "Adaptec 29320B Ultra320 SCSI adapter",
                ahd_aic7902_setup
        },
-       {
-               ID_AHA_29320LP,
-               ID_ALL_MASK,
-               "Adaptec 29320LP Ultra320 SCSI adapter",
-               ahd_aic7901A_setup
-       },
        {
                ID_AHA_39320,
                ID_ALL_MASK,
@@ -145,6 +144,12 @@ struct ahd_pci_identity ahd_pci_ident_table [] =
                "Adaptec 39320 Ultra320 SCSI adapter",
                ahd_aic7902_setup
        },
+       {
+               ID_AHA_39320_B_DELL,
+               ID_ALL_MASK,
+               "Adaptec (Dell OEM) 39320 Ultra320 SCSI adapter",
+               ahd_aic7902_setup
+       },
        {
                ID_AHA_39320A,
                ID_ALL_MASK,
@@ -668,6 +673,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
         * Now set the termination based on what we found.
         */
        sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN;
+       ahd->flags &= ~AHD_TERM_ENB_A;
        if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) {
                ahd->flags |= AHD_TERM_ENB_A;
                sxfrctl1 |= STPWEN;
index b5cfeabdfecf1cee196c37c57d23da4f1a40efa0..da45153668c7589587c4a3a831125c26d24db66d 100644 (file)
 #define ID_AHA_29320ALP                        0x8017900500449005ull
 
 #define ID_AIC7901A                    0x801E9005FFFF9005ull
-#define ID_AHA_29320                   0x8012900500429005ull
-#define ID_AHA_29320B                  0x8013900500439005ull
 #define ID_AHA_29320LP                 0x8014900500449005ull
 
 #define ID_AIC7902                     0x801F9005FFFF9005ull
 #define ID_AIC7902_B                   0x801D9005FFFF9005ull
 #define ID_AHA_39320                   0x8010900500409005ull
+#define ID_AHA_29320                   0x8012900500429005ull
+#define ID_AHA_29320B                  0x8013900500439005ull
 #define ID_AHA_39320_B                 0x8015900500409005ull
+#define ID_AHA_39320_B_DELL            0x8015900501681028ull
 #define ID_AHA_39320A                  0x8016900500409005ull
 #define ID_AHA_39320D                  0x8011900500419005ull
 #define ID_AHA_39320D_B                        0x801C900500419005ull
index c01ac39090d98d02473734cfce5118ce6198f43c..8763b158856b56aef0dd856c55cafe1a89c11c43 100644 (file)
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *              from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $
  */
 typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahd_reg_parse_entry {
@@ -83,17 +83,17 @@ ahd_reg_print_t ahd_hs_mailbox_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrseqintstat_print;
+ahd_reg_print_t ahd_seqintstat_print;
 #else
-#define ahd_clrseqintstat_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CLRSEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
+#define ahd_seqintstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_seqintstat_print;
+ahd_reg_print_t ahd_clrseqintstat_print;
 #else
-#define ahd_seqintstat_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
+#define ahd_clrseqintstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -412,17 +412,17 @@ ahd_reg_print_t ahd_sxfrctl0_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_businitid_print;
+ahd_reg_print_t ahd_dlcount_print;
 #else
-#define ahd_businitid_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "BUSINITID", 0x3c, regvalue, cur_col, wrap)
+#define ahd_dlcount_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DLCOUNT", 0x3c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dlcount_print;
+ahd_reg_print_t ahd_businitid_print;
 #else
-#define ahd_dlcount_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DLCOUNT", 0x3c, regvalue, cur_col, wrap)
+#define ahd_businitid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BUSINITID", 0x3c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -516,13 +516,6 @@ ahd_reg_print_t ahd_selid_print;
     ahd_print_register(NULL, 0, "SELID", 0x49, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sblkctl_print;
-#else
-#define ahd_sblkctl_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SBLKCTL", 0x4a, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_optionmode_print;
 #else
@@ -531,10 +524,10 @@ ahd_reg_print_t ahd_optionmode_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sstat0_print;
+ahd_reg_print_t ahd_sblkctl_print;
 #else
-#define ahd_sstat0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SSTAT0", 0x4b, regvalue, cur_col, wrap)
+#define ahd_sblkctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SBLKCTL", 0x4a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -544,6 +537,13 @@ ahd_reg_print_t ahd_clrsint0_print;
     ahd_print_register(NULL, 0, "CLRSINT0", 0x4b, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sstat0_print;
+#else
+#define ahd_sstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SSTAT0", 0x4b, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_simode0_print;
 #else
@@ -573,17 +573,17 @@ ahd_reg_print_t ahd_sstat2_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_clrsint2_print;
+ahd_reg_print_t ahd_simode2_print;
 #else
-#define ahd_clrsint2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CLRSINT2", 0x4d, regvalue, cur_col, wrap)
+#define ahd_simode2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SIMODE2", 0x4d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_simode2_print;
+ahd_reg_print_t ahd_clrsint2_print;
 #else
-#define ahd_simode2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SIMODE2", 0x4d, regvalue, cur_col, wrap)
+#define ahd_clrsint2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSINT2", 0x4d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -684,13 +684,6 @@ ahd_reg_print_t ahd_clrsint3_print;
     ahd_print_register(NULL, 0, "CLRSINT3", 0x53, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqomode0_print;
-#else
-#define ahd_lqomode0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LQOMODE0", 0x54, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lqostat0_print;
 #else
@@ -705,6 +698,20 @@ ahd_reg_print_t ahd_clrlqoint0_print;
     ahd_print_register(NULL, 0, "CLRLQOINT0", 0x54, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqomode0_print;
+#else
+#define ahd_lqomode0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOMODE0", 0x54, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqomode1_print;
+#else
+#define ahd_lqomode1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOMODE1", 0x55, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lqostat1_print;
 #else
@@ -719,13 +726,6 @@ ahd_reg_print_t ahd_clrlqoint1_print;
     ahd_print_register(NULL, 0, "CLRLQOINT1", 0x55, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_lqomode1_print;
-#else
-#define ahd_lqomode1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LQOMODE1", 0x55, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lqostat2_print;
 #else
@@ -909,17 +909,17 @@ ahd_reg_print_t ahd_annexcol_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scschkn_print;
+ahd_reg_print_t ahd_annexdat_print;
 #else
-#define ahd_scschkn_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCSCHKN", 0x66, regvalue, cur_col, wrap)
+#define ahd_annexdat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ANNEXDAT", 0x66, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_annexdat_print;
+ahd_reg_print_t ahd_scschkn_print;
 #else
-#define ahd_annexdat_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ANNEXDAT", 0x66, regvalue, cur_col, wrap)
+#define ahd_scschkn_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSCHKN", 0x66, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1000,17 +1000,17 @@ ahd_reg_print_t ahd_pll400ctl1_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_pll400cnt0_print;
+ahd_reg_print_t ahd_unfairness_print;
 #else
-#define ahd_pll400cnt0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "PLL400CNT0", 0x6e, regvalue, cur_col, wrap)
+#define ahd_unfairness_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "UNFAIRNESS", 0x6e, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_unfairness_print;
+ahd_reg_print_t ahd_pll400cnt0_print;
 #else
-#define ahd_unfairness_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "UNFAIRNESS", 0x6e, regvalue, cur_col, wrap)
+#define ahd_pll400cnt0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL400CNT0", 0x6e, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1055,13 +1055,6 @@ ahd_reg_print_t ahd_hodmaen_print;
     ahd_print_register(NULL, 0, "HODMAEN", 0x7a, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sghaddr_print;
-#else
-#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_scbhaddr_print;
 #else
@@ -1070,10 +1063,10 @@ ahd_reg_print_t ahd_scbhaddr_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sghcnt_print;
+ahd_reg_print_t ahd_sghaddr_print;
 #else
-#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
+#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1083,6 +1076,13 @@ ahd_reg_print_t ahd_scbhcnt_print;
     ahd_print_register(NULL, 0, "SCBHCNT", 0x84, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sghcnt_print;
+#else
+#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dff_thrsh_print;
 #else
@@ -1153,13 +1153,6 @@ ahd_reg_print_t ahd_nsenable_print;
     ahd_print_register(NULL, 0, "NSENABLE", 0x91, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg1_print;
-#else
-#define ahd_dchrxmsg1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DCHRXMSG1", 0x91, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmcrxmsg1_print;
 #else
@@ -1168,17 +1161,17 @@ ahd_reg_print_t ahd_cmcrxmsg1_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchrxmsg2_print;
+ahd_reg_print_t ahd_dchrxmsg1_print;
 #else
-#define ahd_dchrxmsg2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DCHRXMSG2", 0x92, regvalue, cur_col, wrap)
+#define ahd_dchrxmsg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG1", 0x91, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg2_print;
+ahd_reg_print_t ahd_dchrxmsg2_print;
 #else
-#define ahd_ovlyrxmsg2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "OVLYRXMSG2", 0x92, regvalue, cur_col, wrap)
+#define ahd_dchrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG2", 0x92, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1195,6 +1188,13 @@ ahd_reg_print_t ahd_ost_print;
     ahd_print_register(NULL, 0, "OST", 0x92, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg2_print;
+#else
+#define ahd_ovlyrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG2", 0x92, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dchrxmsg3_print;
 #else
@@ -1202,6 +1202,13 @@ ahd_reg_print_t ahd_dchrxmsg3_print;
     ahd_print_register(NULL, 0, "DCHRXMSG3", 0x93, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg3_print;
+#else
+#define ahd_ovlyrxmsg3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG3", 0x93, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmcrxmsg3_print;
 #else
@@ -1216,13 +1223,6 @@ ahd_reg_print_t ahd_pcixctl_print;
     ahd_print_register(NULL, 0, "PCIXCTL", 0x93, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyrxmsg3_print;
-#else
-#define ahd_ovlyrxmsg3_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "OVLYRXMSG3", 0x93, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_ovlyseqbcnt_print;
 #else
@@ -1230,13 +1230,6 @@ ahd_reg_print_t ahd_ovlyseqbcnt_print;
     ahd_print_register(NULL, 0, "OVLYSEQBCNT", 0x94, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcseqbcnt_print;
-#else
-#define ahd_cmcseqbcnt_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMCSEQBCNT", 0x94, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dchseqbcnt_print;
 #else
@@ -1245,17 +1238,17 @@ ahd_reg_print_t ahd_dchseqbcnt_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_cmcspltstat0_print;
+ahd_reg_print_t ahd_cmcseqbcnt_print;
 #else
-#define ahd_cmcspltstat0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMCSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
+#define ahd_cmcseqbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCSEQBCNT", 0x94, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ovlyspltstat0_print;
+ahd_reg_print_t ahd_cmcspltstat0_print;
 #else
-#define ahd_ovlyspltstat0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "OVLYSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
+#define ahd_cmcspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1266,10 +1259,10 @@ ahd_reg_print_t ahd_dchspltstat0_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dchspltstat1_print;
+ahd_reg_print_t ahd_ovlyspltstat0_print;
 #else
-#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DCHSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#define ahd_ovlyspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1286,6 +1279,13 @@ ahd_reg_print_t ahd_ovlyspltstat1_print;
     ahd_print_register(NULL, 0, "OVLYSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchspltstat1_print;
+#else
+#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_sgrxmsg0_print;
 #else
@@ -1378,17 +1378,17 @@ ahd_reg_print_t ahd_sgspltstat0_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sfunct_print;
+ahd_reg_print_t ahd_sgspltstat1_print;
 #else
-#define ahd_sfunct_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
+#define ahd_sgspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGSPLTSTAT1", 0x9f, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_sgspltstat1_print;
+ahd_reg_print_t ahd_sfunct_print;
 #else
-#define ahd_sgspltstat1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SGSPLTSTAT1", 0x9f, regvalue, cur_col, wrap)
+#define ahd_sfunct_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1504,17 +1504,17 @@ ahd_reg_print_t ahd_ccsgaddr_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccscbaddr_print;
+ahd_reg_print_t ahd_ccscbadr_bk_print;
 #else
-#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CCSCBADDR", 0xac, regvalue, cur_col, wrap)
+#define ahd_ccscbadr_bk_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBADR_BK", 0xac, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccscbadr_bk_print;
+ahd_reg_print_t ahd_ccscbaddr_print;
 #else
-#define ahd_ccscbadr_bk_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CCSCBADR_BK", 0xac, regvalue, cur_col, wrap)
+#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBADDR", 0xac, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1525,17 +1525,17 @@ ahd_reg_print_t ahd_cmc_rambist_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccsgctl_print;
+ahd_reg_print_t ahd_ccscbctl_print;
 #else
-#define ahd_ccsgctl_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CCSGCTL", 0xad, regvalue, cur_col, wrap)
+#define ahd_ccscbctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBCTL", 0xad, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_ccscbctl_print;
+ahd_reg_print_t ahd_ccsgctl_print;
 #else
-#define ahd_ccscbctl_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CCSCBCTL", 0xad, regvalue, cur_col, wrap)
+#define ahd_ccsgctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSGCTL", 0xad, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1706,13 +1706,6 @@ ahd_reg_print_t ahd_wrtbiascalc_print;
     ahd_print_register(NULL, 0, "WRTBIASCALC", 0xc7, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfptrs_print;
-#else
-#define ahd_dfptrs_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DFPTRS", 0xc8, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_rcvrbiascalc_print;
 #else
@@ -1721,10 +1714,10 @@ ahd_reg_print_t ahd_rcvrbiascalc_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_dfbkptr_print;
+ahd_reg_print_t ahd_dfptrs_print;
 #else
-#define ahd_dfbkptr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DFBKPTR", 0xc9, regvalue, cur_col, wrap)
+#define ahd_dfptrs_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFPTRS", 0xc8, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1734,6 +1727,13 @@ ahd_reg_print_t ahd_skewcalc_print;
     ahd_print_register(NULL, 0, "SKEWCALC", 0xc9, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfbkptr_print;
+#else
+#define ahd_dfbkptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFBKPTR", 0xc9, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dfdbctl_print;
 #else
@@ -1826,17 +1826,17 @@ ahd_reg_print_t ahd_dindex_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_brkaddr1_print;
+ahd_reg_print_t ahd_brkaddr0_print;
 #else
-#define ahd_brkaddr1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "BRKADDR1", 0xe6, regvalue, cur_col, wrap)
+#define ahd_brkaddr0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRKADDR0", 0xe6, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_brkaddr0_print;
+ahd_reg_print_t ahd_brkaddr1_print;
 #else
-#define ahd_brkaddr0_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "BRKADDR0", 0xe6, regvalue, cur_col, wrap)
+#define ahd_brkaddr1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRKADDR1", 0xe6, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1888,13 +1888,6 @@ ahd_reg_print_t ahd_stack_print;
     ahd_print_register(NULL, 0, "STACK", 0xf2, regvalue, cur_col, wrap)
 #endif
 
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_curaddr_print;
-#else
-#define ahd_curaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CURADDR", 0xf4, regvalue, cur_col, wrap)
-#endif
-
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_intvec1_addr_print;
 #else
@@ -1903,10 +1896,10 @@ ahd_reg_print_t ahd_intvec1_addr_print;
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_intvec2_addr_print;
+ahd_reg_print_t ahd_curaddr_print;
 #else
-#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INTVEC2_ADDR", 0xf6, regvalue, cur_col, wrap)
+#define ahd_curaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CURADDR", 0xf4, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -1916,6 +1909,13 @@ ahd_reg_print_t ahd_lastaddr_print;
     ahd_print_register(NULL, 0, "LASTADDR", 0xf6, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_intvec2_addr_print;
+#else
+#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INTVEC2_ADDR", 0xf6, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_longjmp_addr_print;
 #else
@@ -1993,193 +1993,214 @@ ahd_reg_print_t ahd_complete_dma_scb_head_print;
     ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_HEAD", 0x12c, regvalue, cur_col, wrap)
 #endif
 
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_dma_scb_tail_print;
+#else
+#define ahd_complete_dma_scb_tail_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_TAIL", 0x12e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_on_qfreeze_head_print;
+#else
+#define ahd_complete_on_qfreeze_head_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_ON_QFREEZE_HEAD", 0x130, regvalue, cur_col, wrap)
+#endif
+
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_qfreeze_count_print;
 #else
 #define ahd_qfreeze_count_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "QFREEZE_COUNT", 0x12e, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "QFREEZE_COUNT", 0x132, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_kernel_qfreeze_count_print;
+#else
+#define ahd_kernel_qfreeze_count_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "KERNEL_QFREEZE_COUNT", 0x134, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_saved_mode_print;
 #else
 #define ahd_saved_mode_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SAVED_MODE", 0x130, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SAVED_MODE", 0x136, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_msg_out_print;
 #else
 #define ahd_msg_out_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "MSG_OUT", 0x131, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "MSG_OUT", 0x137, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_dmaparams_print;
 #else
 #define ahd_dmaparams_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "DMAPARAMS", 0x132, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "DMAPARAMS", 0x138, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_seq_flags_print;
 #else
 #define ahd_seq_flags_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SEQ_FLAGS", 0x133, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SEQ_FLAGS", 0x139, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_saved_scsiid_print;
 #else
 #define ahd_saved_scsiid_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SAVED_SCSIID", 0x134, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SAVED_SCSIID", 0x13a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_saved_lun_print;
 #else
 #define ahd_saved_lun_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SAVED_LUN", 0x135, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SAVED_LUN", 0x13b, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_lastphase_print;
 #else
 #define ahd_lastphase_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LASTPHASE", 0x136, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "LASTPHASE", 0x13c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_qoutfifo_entry_valid_tag_print;
 #else
 #define ahd_qoutfifo_entry_valid_tag_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG", 0x137, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG", 0x13d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_shared_data_addr_print;
+ahd_reg_print_t ahd_kernel_tqinpos_print;
 #else
-#define ahd_shared_data_addr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x138, regvalue, cur_col, wrap)
+#define ahd_kernel_tqinpos_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "KERNEL_TQINPOS", 0x13e, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_qoutfifo_next_addr_print;
+ahd_reg_print_t ahd_tqinpos_print;
 #else
-#define ahd_qoutfifo_next_addr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR", 0x13c, regvalue, cur_col, wrap)
+#define ahd_tqinpos_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TQINPOS", 0x13f, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_kernel_tqinpos_print;
+ahd_reg_print_t ahd_shared_data_addr_print;
 #else
-#define ahd_kernel_tqinpos_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "KERNEL_TQINPOS", 0x140, regvalue, cur_col, wrap)
+#define ahd_shared_data_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x140, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_tqinpos_print;
+ahd_reg_print_t ahd_qoutfifo_next_addr_print;
 #else
-#define ahd_tqinpos_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "TQINPOS", 0x141, regvalue, cur_col, wrap)
+#define ahd_qoutfifo_next_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR", 0x144, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_arg_1_print;
 #else
 #define ahd_arg_1_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ARG_1", 0x142, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ARG_1", 0x148, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_arg_2_print;
 #else
 #define ahd_arg_2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ARG_2", 0x143, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ARG_2", 0x149, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_last_msg_print;
 #else
 #define ahd_last_msg_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LAST_MSG", 0x144, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "LAST_MSG", 0x14a, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_scsiseq_template_print;
 #else
 #define ahd_scsiseq_template_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x145, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x14b, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_initiator_tag_print;
 #else
 #define ahd_initiator_tag_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INITIATOR_TAG", 0x146, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INITIATOR_TAG", 0x14c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_seq_flags2_print;
 #else
 #define ahd_seq_flags2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SEQ_FLAGS2", 0x147, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "SEQ_FLAGS2", 0x14d, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_allocfifo_scbptr_print;
 #else
 #define ahd_allocfifo_scbptr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR", 0x148, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR", 0x14e, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_timer_print;
 #else
 #define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x150, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_maxcmds_print;
 #else
 #define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x152, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_mincmds_print;
 #else
 #define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x153, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmds_pending_print;
 #else
 #define ahd_cmds_pending_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMDS_PENDING", 0x14e, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "CMDS_PENDING", 0x154, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_int_coalescing_cmdcount_print;
 #else
 #define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x156, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_local_hs_mailbox_print;
 #else
 #define ahd_local_hs_mailbox_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX", 0x151, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX", 0x157, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_cmdsize_table_print;
 #else
 #define ahd_cmdsize_table_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x152, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x158, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2434,13 +2455,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                HOST_TQINPOS            0x80
 #define                ENINT_COALESCE          0x40
 
-#define        CLRSEQINTSTAT                   0x0c
-#define                CLRSEQ_SWTMRTO          0x10
-#define                CLRSEQ_SEQINT           0x08
-#define                CLRSEQ_SCSIINT          0x04
-#define                CLRSEQ_PCIINT           0x02
-#define                CLRSEQ_SPLTINT          0x01
-
 #define        SEQINTSTAT                      0x0c
 #define                SEQ_SWTMRTO             0x10
 #define                SEQ_SEQINT              0x08
@@ -2448,6 +2462,13 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                SEQ_PCIINT              0x02
 #define                SEQ_SPLTINT             0x01
 
+#define        CLRSEQINTSTAT                   0x0c
+#define                CLRSEQ_SWTMRTO          0x10
+#define                CLRSEQ_SEQINT           0x08
+#define                CLRSEQ_SCSIINT          0x04
+#define                CLRSEQ_PCIINT           0x02
+#define                CLRSEQ_SPLTINT          0x01
+
 #define        SWTIMER                         0x0e
 
 #define        SNSCB_QOFF                      0x10
@@ -2623,10 +2644,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                BIOSCANCELEN            0x10
 #define                SPIOEN                  0x08
 
-#define        BUSINITID                       0x3c
-
 #define        DLCOUNT                         0x3c
 
+#define        BUSINITID                       0x3c
+
 #define        SXFRCTL1                        0x3d
 #define                BITBUCKET               0x80
 #define                ENSACHK                 0x40
@@ -2693,13 +2714,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                SELID_MASK              0xf0
 #define                ONEBIT                  0x08
 
-#define        SBLKCTL                         0x4a
-#define                DIAGLEDEN               0x80
-#define                DIAGLEDON               0x40
-#define                ENAB40                  0x08
-#define                ENAB20                  0x04
-#define                SELWIDE                 0x02
-
 #define        OPTIONMODE                      0x4a
 #define                OPTIONMODE_DEFAULTS     0x02
 #define                BIOSCANCTL              0x80
@@ -2709,15 +2723,12 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                ENDGFORMCHK             0x04
 #define                AUTO_MSGOUT_DE          0x02
 
-#define        SSTAT0                          0x4b
-#define                TARGET                  0x80
-#define                SELDO                   0x40
-#define                SELDI                   0x20
-#define                SELINGO                 0x10
-#define                IOERR                   0x08
-#define                OVERRUN                 0x04
-#define                SPIORDY                 0x02
-#define                ARBDO                   0x01
+#define        SBLKCTL                         0x4a
+#define                DIAGLEDEN               0x80
+#define                DIAGLEDON               0x40
+#define                ENAB40                  0x08
+#define                ENAB20                  0x04
+#define                SELWIDE                 0x02
 
 #define        CLRSINT0                        0x4b
 #define                CLRSELDO                0x40
@@ -2728,6 +2739,16 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CLRSPIORDY              0x02
 #define                CLRARBDO                0x01
 
+#define        SSTAT0                          0x4b
+#define                TARGET                  0x80
+#define                SELDO                   0x40
+#define                SELDI                   0x20
+#define                SELINGO                 0x10
+#define                IOERR                   0x08
+#define                OVERRUN                 0x04
+#define                SPIORDY                 0x02
+#define                ARBDO                   0x01
+
 #define        SIMODE0                         0x4b
 #define                ENSELDO                 0x40
 #define                ENSELDI                 0x20
@@ -2768,17 +2789,17 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                BUSFREE_DFF0            0x80
 #define                BUSFREE_LQO             0x40
 
+#define        SIMODE2                         0x4d
+#define                ENWIDE_RES              0x04
+#define                ENSDONE                 0x02
+#define                ENDMADONE               0x01
+
 #define        CLRSINT2                        0x4d
 #define                CLRNONPACKREQ           0x20
 #define                CLRWIDE_RES             0x04
 #define                CLRSDONE                0x02
 #define                CLRDMADONE              0x01
 
-#define        SIMODE2                         0x4d
-#define                ENWIDE_RES              0x04
-#define                ENSDONE                 0x02
-#define                ENDMADONE               0x01
-
 #define        PERRDIAG                        0x4e
 #define                HIZERO                  0x80
 #define                HIPERR                  0x40
@@ -2871,13 +2892,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CLRNTRAMPERR            0x02
 #define                CLROSRAMPERR            0x01
 
-#define        LQOMODE0                        0x54
-#define                ENLQOTARGSCBPERR        0x10
-#define                ENLQOSTOPT2             0x08
-#define                ENLQOATNLQ              0x04
-#define                ENLQOATNPKT             0x02
-#define                ENLQOTCRC               0x01
-
 #define        LQOSTAT0                        0x54
 #define                LQOTARGSCBPERR          0x10
 #define                LQOSTOPT2               0x08
@@ -2892,6 +2906,20 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CLRLQOATNPKT            0x02
 #define                CLRLQOTCRC              0x01
 
+#define        LQOMODE0                        0x54
+#define                ENLQOTARGSCBPERR        0x10
+#define                ENLQOSTOPT2             0x08
+#define                ENLQOATNLQ              0x04
+#define                ENLQOATNPKT             0x02
+#define                ENLQOTCRC               0x01
+
+#define        LQOMODE1                        0x55
+#define                ENLQOINITSCBPERR        0x10
+#define                ENLQOSTOPI2             0x08
+#define                ENLQOBADQAS             0x04
+#define                ENLQOBUSFREE            0x02
+#define                ENLQOPHACHGINPKT        0x01
+
 #define        LQOSTAT1                        0x55
 #define                LQOINITSCBPERR          0x10
 #define                LQOSTOPI2               0x08
@@ -2906,13 +2934,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CLRLQOBUSFREE           0x02
 #define                CLRLQOPHACHGINPKT       0x01
 
-#define        LQOMODE1                        0x55
-#define                ENLQOINITSCBPERR        0x10
-#define                ENLQOSTOPI2             0x08
-#define                ENLQOBADQAS             0x04
-#define                ENLQOBUSFREE            0x02
-#define                ENLQOPHACHGINPKT        0x01
-
 #define        LQOSTAT2                        0x56
 #define                LQOPKT                  0xe0
 #define                LQOWAITFIFO             0x10
@@ -3028,6 +3049,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        ANNEXCOL                        0x65
 
+#define        ANNEXDAT                        0x66
+
 #define        SCSCHKN                         0x66
 #define                STSELSKIDDIS            0x40
 #define                CURRFIFODEF             0x20
@@ -3037,8 +3060,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                SHVALIDSTDIS            0x02
 #define                LSTSGCLRDIS             0x01
 
-#define        ANNEXDAT                        0x66
-
 #define        IOWNID                          0x67
 
 #define        PLL960CTL0                      0x68
@@ -3071,10 +3092,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                PLL_CNTCLR              0x40
 #define                PLL_RST                 0x01
 
-#define        PLL400CNT0                      0x6e
-
 #define        UNFAIRNESS                      0x6e
 
+#define        PLL400CNT0                      0x6e
+
 #define        HADDR                           0x70
 
 #define        PLLDELAY                        0x70
@@ -3088,14 +3109,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        HODMAEN                         0x7a
 
-#define        SGHADDR                         0x7c
-
 #define        SCBHADDR                        0x7c
 
-#define        SGHCNT                          0x84
+#define        SGHADDR                         0x7c
 
 #define        SCBHCNT                         0x84
 
+#define        SGHCNT                          0x84
+
 #define        DFF_THRSH                       0x88
 #define                WR_DFTHRSH              0x70
 #define                RD_DFTHRSH              0x07
@@ -3113,8 +3134,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                RD_DFTHRSH_63           0x03
 #define                RD_DFTHRSH_50           0x02
 #define                RD_DFTHRSH_25           0x01
-#define                WR_DFTHRSH_MIN          0x00
 #define                RD_DFTHRSH_MIN          0x00
+#define                WR_DFTHRSH_MIN          0x00
 
 #define        ROMADDR                         0x8a
 
@@ -3150,20 +3171,22 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                DCH1NSEN                0x02
 #define                DCH0NSEN                0x01
 
-#define        DCHRXMSG1                       0x91
-
 #define        CMCRXMSG1                       0x91
 
-#define        DCHRXMSG2                       0x92
+#define        DCHRXMSG1                       0x91
 
-#define        OVLYRXMSG2                      0x92
+#define        DCHRXMSG2                       0x92
 
 #define        CMCRXMSG2                       0x92
 
 #define        OST                             0x92
 
+#define        OVLYRXMSG2                      0x92
+
 #define        DCHRXMSG3                       0x93
 
+#define        OVLYRXMSG3                      0x93
+
 #define        CMCRXMSG3                       0x93
 
 #define        PCIXCTL                         0x93
@@ -3175,26 +3198,24 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                TSCSERREN               0x02
 #define                CMPABCDIS               0x01
 
-#define        OVLYRXMSG3                      0x93
-
 #define        OVLYSEQBCNT                     0x94
 
-#define        CMCSEQBCNT                      0x94
-
 #define        DCHSEQBCNT                      0x94
 
-#define        CMCSPLTSTAT0                    0x96
+#define        CMCSEQBCNT                      0x94
 
-#define        OVLYSPLTSTAT0                   0x96
+#define        CMCSPLTSTAT0                    0x96
 
 #define        DCHSPLTSTAT0                    0x96
 
-#define        DCHSPLTSTAT1                    0x97
+#define        OVLYSPLTSTAT0                   0x96
 
 #define        CMCSPLTSTAT1                    0x97
 
 #define        OVLYSPLTSTAT1                   0x97
 
+#define        DCHSPLTSTAT1                    0x97
+
 #define        SGRXMSG0                        0x98
 #define                CDNUM                   0xf8
 #define                CFNUM                   0x07
@@ -3244,13 +3265,13 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                RXSCEMSG                0x02
 #define                RXSPLTRSP               0x01
 
+#define        SGSPLTSTAT1                     0x9f
+#define                RXDATABUCKET            0x01
+
 #define        SFUNCT                          0x9f
 #define                TEST_GROUP              0xf0
 #define                TEST_NUM                0x0f
 
-#define        SGSPLTSTAT1                     0x9f
-#define                RXDATABUCKET            0x01
-
 #define        DF0PCISTAT                      0xa0
 
 #define        REG0                            0xa0
@@ -3299,10 +3320,10 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        CCSGADDR                        0xac
 
-#define        CCSCBADDR                       0xac
-
 #define        CCSCBADR_BK                     0xac
 
+#define        CCSCBADDR                       0xac
+
 #define        CMC_RAMBIST                     0xad
 #define                SG_ELEMENT_SIZE         0x80
 #define                SCBRAMBIST_FAIL         0x40
@@ -3311,14 +3332,6 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CMC_BUFFER_BIST_FAIL    0x02
 #define                CMC_BUFFER_BIST_EN      0x01
 
-#define        CCSGCTL                         0xad
-#define                CCSGEN                  0x0c
-#define                CCSGDONE                0x80
-#define                SG_CACHE_AVAIL          0x10
-#define                CCSGENACK               0x08
-#define                SG_FETCH_REQ            0x02
-#define                CCSGRESET               0x01
-
 #define        CCSCBCTL                        0xad
 #define                CCSCBDONE               0x80
 #define                ARRDONE                 0x40
@@ -3327,6 +3340,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CCSCBDIR                0x04
 #define                CCSCBRESET              0x01
 
+#define        CCSGCTL                         0xad
+#define                CCSGEN                  0x0c
+#define                CCSGDONE                0x80
+#define                SG_CACHE_AVAIL          0x10
+#define                CCSGENACK               0x08
+#define                SG_FETCH_REQ            0x02
+#define                CCSGRESET               0x01
+
 #define        CCSGRAM                         0xb0
 
 #define        FLEXADR                         0xb0
@@ -3356,8 +3377,8 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define        SEEDAT                          0xbc
 
 #define        SEECTL                          0xbe
-#define                SEEOP_EWEN              0x40
 #define                SEEOP_WALL              0x40
+#define                SEEOP_EWEN              0x40
 #define                SEEOP_EWDS              0x40
 #define                SEEOPCODE               0x70
 #define                SEERST                  0x02
@@ -3414,14 +3435,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        WRTBIASCALC                     0xc7
 
-#define        DFPTRS                          0xc8
-
 #define        RCVRBIASCALC                    0xc8
 
-#define        DFBKPTR                         0xc9
+#define        DFPTRS                          0xc8
 
 #define        SKEWCALC                        0xc9
 
+#define        DFBKPTR                         0xc9
+
 #define        DFDBCTL                         0xcb
 #define                DFF_CIO_WR_RDY          0x20
 #define                DFF_CIO_RD_RDY          0x10
@@ -3475,11 +3496,11 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        DINDEX                          0xe4
 
+#define        BRKADDR0                        0xe6
+
 #define        BRKADDR1                        0xe6
 #define                BRKDIS                  0x80
 
-#define        BRKADDR0                        0xe6
-
 #define        ALLONES                         0xe8
 
 #define        ALLZEROS                        0xea
@@ -3494,14 +3515,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        STACK                           0xf2
 
-#define        CURADDR                         0xf4
-
 #define        INTVEC1_ADDR                    0xf4
 
-#define        INTVEC2_ADDR                    0xf6
+#define        CURADDR                         0xf4
 
 #define        LASTADDR                        0xf6
 
+#define        INTVEC2_ADDR                    0xf6
+
 #define        LONGJMP_ADDR                    0xf8
 
 #define        ACCUM_SAVE                      0xfa
@@ -3524,25 +3545,31 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 #define        COMPLETE_DMA_SCB_HEAD           0x12c
 
-#define        QFREEZE_COUNT                   0x12e
+#define        COMPLETE_DMA_SCB_TAIL           0x12e
+
+#define        COMPLETE_ON_QFREEZE_HEAD                0x130
+
+#define        QFREEZE_COUNT                   0x132
 
-#define        SAVED_MODE                      0x130
+#define        KERNEL_QFREEZE_COUNT            0x134
 
-#define        MSG_OUT                         0x131
+#define        SAVED_MODE                      0x136
 
-#define        DMAPARAMS                       0x132
+#define        MSG_OUT                         0x137
+
+#define        DMAPARAMS                       0x138
 #define                PRELOADEN               0x80
 #define                WIDEODD                 0x40
 #define                SCSIEN                  0x20
 #define                SDMAEN                  0x10
 #define                SDMAENACK               0x10
-#define                HDMAENACK               0x08
 #define                HDMAEN                  0x08
+#define                HDMAENACK               0x08
 #define                DIRECTION               0x04
 #define                FIFOFLUSH               0x02
 #define                FIFORESET               0x01
 
-#define        SEQ_FLAGS                       0x133
+#define        SEQ_FLAGS                       0x139
 #define                NOT_IDENTIFIED          0x80
 #define                NO_CDB_SENT             0x40
 #define                TARGET_CMD_IS_TAGGED    0x40
@@ -3553,11 +3580,11 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                SPHASE_PENDING          0x02
 #define                NO_DISCONNECT           0x01
 
-#define        SAVED_SCSIID                    0x134
+#define        SAVED_SCSIID                    0x13a
 
-#define        SAVED_LUN                       0x135
+#define        SAVED_LUN                       0x13b
 
-#define        LASTPHASE                       0x136
+#define        LASTPHASE                       0x13c
 #define                PHASE_MASK              0xe0
 #define                CDI                     0x80
 #define                IOI                     0x40
@@ -3572,18 +3599,18 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                P_DATAOUT_DT            0x20
 #define                P_DATAOUT               0x00
 
-#define        QOUTFIFO_ENTRY_VALID_TAG                0x137
+#define        QOUTFIFO_ENTRY_VALID_TAG                0x13d
 
-#define        SHARED_DATA_ADDR                0x138
+#define        KERNEL_TQINPOS                  0x13e
 
-#define        QOUTFIFO_NEXT_ADDR              0x13c
+#define        TQINPOS                         0x13f
 
-#define        KERNEL_TQINPOS                  0x140
+#define        SHARED_DATA_ADDR                0x140
 
-#define        TQINPOS                         0x141
+#define        QOUTFIFO_NEXT_ADDR              0x144
 
-#define        ARG_1                           0x142
-#define        RETURN_1                        0x142
+#define        ARG_1                           0x148
+#define        RETURN_1                        0x148
 #define                SEND_MSG                0x80
 #define                SEND_SENSE              0x40
 #define                SEND_REJ                0x20
@@ -3593,12 +3620,12 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                CONT_MSG_LOOP_READ      0x03
 #define                CONT_MSG_LOOP_TARG      0x02
 
-#define        ARG_2                           0x143
-#define        RETURN_2                        0x143
+#define        ARG_2                           0x149
+#define        RETURN_2                        0x149
 
-#define        LAST_MSG                        0x144
+#define        LAST_MSG                        0x14a
 
-#define        SCSISEQ_TEMPLATE                0x145
+#define        SCSISEQ_TEMPLATE                0x14b
 #define                MANUALCTL               0x40
 #define                ENSELI                  0x20
 #define                ENRSELI                 0x10
@@ -3606,27 +3633,27 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define                ENAUTOATNP              0x02
 #define                ALTSTIM                 0x01
 
-#define        INITIATOR_TAG                   0x146
+#define        INITIATOR_TAG                   0x14c
 
-#define        SEQ_FLAGS2                      0x147
+#define        SEQ_FLAGS2                      0x14d
 #define                SELECTOUT_QFROZEN       0x04
 #define                TARGET_MSG_PENDING      0x02
 
-#define        ALLOCFIFO_SCBPTR                0x148
+#define        ALLOCFIFO_SCBPTR                0x14e
 
-#define        INT_COALESCING_TIMER            0x14a
+#define        INT_COALESCING_TIMER            0x150
 
-#define        INT_COALESCING_MAXCMDS          0x14c
+#define        INT_COALESCING_MAXCMDS          0x152
 
-#define        INT_COALESCING_MINCMDS          0x14d
+#define        INT_COALESCING_MINCMDS          0x153
 
-#define        CMDS_PENDING                    0x14e
+#define        CMDS_PENDING                    0x154
 
-#define        INT_COALESCING_CMDCOUNT         0x150
+#define        INT_COALESCING_CMDCOUNT         0x156
 
-#define        LOCAL_HS_MAILBOX                0x151
+#define        LOCAL_HS_MAILBOX                0x157
 
-#define        CMDSIZE_TABLE                   0x152
+#define        CMDSIZE_TABLE                   0x158
 
 #define        SCB_BASE                        0x180
 
@@ -3701,6 +3728,16 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define        SCB_DISCONNECTED_LISTS          0x1b8
 
 
+#define        AHD_TIMER_MAX_US        0x18ffe7
+#define        AHD_TIMER_MAX_TICKS     0xffff
+#define        AHD_SENSE_BUFSIZE       0x100
+#define        BUS_8_BIT       0x00
+#define        TARGET_CMD_CMPLT        0xfe
+#define        SEEOP_WRAL_ADDR 0x40
+#define        AHD_AMPLITUDE_DEF       0x07
+#define        AHD_PRECOMP_CUTBACK_37  0x07
+#define        AHD_PRECOMP_SHIFT       0x00
+#define        AHD_ANNEXCOL_PRECOMP_SLEW       0x04
 #define        AHD_TIMER_US_PER_TICK   0x19
 #define        SCB_TRANSFER_SIZE_FULL_LUN      0x38
 #define        STATUS_QUEUE_FULL       0x28
@@ -3724,28 +3761,18 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define        B_CURRFIFO_0    0x02
 #define        LUNLEN_SINGLE_LEVEL_LUN 0x0f
 #define        NVRAM_SCB_OFFSET        0x2c
-#define        AHD_TIMER_MAX_US        0x18ffe7
-#define        AHD_TIMER_MAX_TICKS     0xffff
 #define        STATUS_PKT_SENSE        0xff
 #define        CMD_GROUP_CODE_SHIFT    0x05
-#define        AHD_SENSE_BUFSIZE       0x100
 #define        MAX_OFFSET_PACED_BUG    0x7f
-#define        BUS_8_BIT       0x00
 #define        STIMESEL_BUG_ADJ        0x08
 #define        STIMESEL_MIN    0x18
 #define        STIMESEL_SHIFT  0x03
 #define        CCSGRAM_MAXSEGS 0x10
 #define        INVALID_ADDR    0x80
-#define        TARGET_CMD_CMPLT        0xfe
-#define        SEEOP_WRAL_ADDR 0x40
 #define        SEEOP_ERAL_ADDR 0x80
-#define        AHD_AMPLITUDE_DEF       0x07
 #define        AHD_SLEWRATE_DEF_REVB   0x08
-#define        AHD_PRECOMP_CUTBACK_37  0x07
 #define        AHD_PRECOMP_CUTBACK_17  0x04
-#define        AHD_PRECOMP_SHIFT       0x00
 #define        AHD_PRECOMP_MASK        0x07
-#define        AHD_ANNEXCOL_PRECOMP_SLEW       0x04
 #define        SRC_MODE_SHIFT  0x00
 #define        PKT_OVERRUN_BUFSIZE     0x200
 #define        SCB_TRANSFER_SIZE_1BYTE_LUN     0x30
@@ -3761,6 +3788,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 
 
 /* Downloaded Constant Definitions */
+#define        CACHELINE_MASK  0x07
 #define        SCB_TRANSFER_SIZE       0x06
 #define        PKT_OVERRUN_BUFOFFSET   0x05
 #define        SG_SIZEOF       0x04
@@ -3768,9 +3796,9 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print;
 #define        SG_PREFETCH_ALIGN_MASK  0x02
 #define        SG_PREFETCH_CNT_LIMIT   0x01
 #define        SG_PREFETCH_CNT 0x00
-#define        DOWNLOAD_CONST_COUNT    0x07
+#define        DOWNLOAD_CONST_COUNT    0x08
 
 
 /* Exported Labels */
-#define        LABEL_seq_isr   0x269
-#define        LABEL_timer_isr 0x265
+#define        LABEL_seq_isr   0x285
+#define        LABEL_timer_isr 0x281
index 3098a757e3d762e32c6fa0877d2565cdf95ef255..a4137c985376b6eabff30ed6a366356eafc4e87a 100644 (file)
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *              from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#118 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#75 $
  */
 
 #include "aic79xx_osm.h"
@@ -172,21 +172,6 @@ ahd_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x0b, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
-       { "CLRSEQ_SPLTINT",     0x01, 0x01 },
-       { "CLRSEQ_PCIINT",      0x02, 0x02 },
-       { "CLRSEQ_SCSIINT",     0x04, 0x04 },
-       { "CLRSEQ_SEQINT",      0x08, 0x08 },
-       { "CLRSEQ_SWTMRTO",     0x10, 0x10 }
-};
-
-int
-ahd_clrseqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(CLRSEQINTSTAT_parse_table, 5, "CLRSEQINTSTAT",
-           0x0c, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t SEQINTSTAT_parse_table[] = {
        { "SEQ_SPLTINT",        0x01, 0x01 },
        { "SEQ_PCIINT",         0x02, 0x02 },
@@ -202,6 +187,21 @@ ahd_seqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x0c, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
+       { "CLRSEQ_SPLTINT",     0x01, 0x01 },
+       { "CLRSEQ_PCIINT",      0x02, 0x02 },
+       { "CLRSEQ_SCSIINT",     0x04, 0x04 },
+       { "CLRSEQ_SEQINT",      0x08, 0x08 },
+       { "CLRSEQ_SWTMRTO",     0x10, 0x10 }
+};
+
+int
+ahd_clrseqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(CLRSEQINTSTAT_parse_table, 5, "CLRSEQINTSTAT",
+           0x0c, regvalue, cur_col, wrap));
+}
+
 int
 ahd_swtimer_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -670,16 +670,16 @@ ahd_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_businitid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dlcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "BUSINITID",
+       return (ahd_print_register(NULL, 0, "DLCOUNT",
            0x3c, regvalue, cur_col, wrap));
 }
 
 int
-ahd_dlcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_businitid_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "DLCOUNT",
+       return (ahd_print_register(NULL, 0, "BUSINITID",
            0x3c, regvalue, cur_col, wrap));
 }
 
@@ -859,21 +859,6 @@ ahd_selid_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x49, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
-       { "SELWIDE",            0x02, 0x02 },
-       { "ENAB20",             0x04, 0x04 },
-       { "ENAB40",             0x08, 0x08 },
-       { "DIAGLEDON",          0x40, 0x40 },
-       { "DIAGLEDEN",          0x80, 0x80 }
-};
-
-int
-ahd_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(SBLKCTL_parse_table, 5, "SBLKCTL",
-           0x4a, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t OPTIONMODE_parse_table[] = {
        { "AUTO_MSGOUT_DE",     0x02, 0x02 },
        { "ENDGFORMCHK",        0x04, 0x04 },
@@ -891,22 +876,19 @@ ahd_optionmode_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x4a, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
-       { "ARBDO",              0x01, 0x01 },
-       { "SPIORDY",            0x02, 0x02 },
-       { "OVERRUN",            0x04, 0x04 },
-       { "IOERR",              0x08, 0x08 },
-       { "SELINGO",            0x10, 0x10 },
-       { "SELDI",              0x20, 0x20 },
-       { "SELDO",              0x40, 0x40 },
-       { "TARGET",             0x80, 0x80 }
+static ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
+       { "SELWIDE",            0x02, 0x02 },
+       { "ENAB20",             0x04, 0x04 },
+       { "ENAB40",             0x08, 0x08 },
+       { "DIAGLEDON",          0x40, 0x40 },
+       { "DIAGLEDEN",          0x80, 0x80 }
 };
 
 int
-ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(SSTAT0_parse_table, 8, "SSTAT0",
-           0x4b, regvalue, cur_col, wrap));
+       return (ahd_print_register(SBLKCTL_parse_table, 5, "SBLKCTL",
+           0x4a, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t CLRSINT0_parse_table[] = {
@@ -926,6 +908,24 @@ ahd_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x4b, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
+       { "ARBDO",              0x01, 0x01 },
+       { "SPIORDY",            0x02, 0x02 },
+       { "OVERRUN",            0x04, 0x04 },
+       { "IOERR",              0x08, 0x08 },
+       { "SELINGO",            0x10, 0x10 },
+       { "SELDI",              0x20, 0x20 },
+       { "SELDO",              0x40, 0x40 },
+       { "TARGET",             0x80, 0x80 }
+};
+
+int
+ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(SSTAT0_parse_table, 8, "SSTAT0",
+           0x4b, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SIMODE0_parse_table[] = {
        { "ENARBDO",            0x01, 0x01 },
        { "ENSPIORDY",          0x02, 0x02 },
@@ -998,30 +998,30 @@ ahd_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x4d, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CLRSINT2_parse_table[] = {
-       { "CLRDMADONE",         0x01, 0x01 },
-       { "CLRSDONE",           0x02, 0x02 },
-       { "CLRWIDE_RES",        0x04, 0x04 },
-       { "CLRNONPACKREQ",      0x20, 0x20 }
+static ahd_reg_parse_entry_t SIMODE2_parse_table[] = {
+       { "ENDMADONE",          0x01, 0x01 },
+       { "ENSDONE",            0x02, 0x02 },
+       { "ENWIDE_RES",         0x04, 0x04 }
 };
 
 int
-ahd_clrsint2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_simode2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(CLRSINT2_parse_table, 4, "CLRSINT2",
+       return (ahd_print_register(SIMODE2_parse_table, 3, "SIMODE2",
            0x4d, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SIMODE2_parse_table[] = {
-       { "ENDMADONE",          0x01, 0x01 },
-       { "ENSDONE",            0x02, 0x02 },
-       { "ENWIDE_RES",         0x04, 0x04 }
+static ahd_reg_parse_entry_t CLRSINT2_parse_table[] = {
+       { "CLRDMADONE",         0x01, 0x01 },
+       { "CLRSDONE",           0x02, 0x02 },
+       { "CLRWIDE_RES",        0x04, 0x04 },
+       { "CLRNONPACKREQ",      0x20, 0x20 }
 };
 
 int
-ahd_simode2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_clrsint2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(SIMODE2_parse_table, 3, "SIMODE2",
+       return (ahd_print_register(CLRSINT2_parse_table, 4, "CLRSINT2",
            0x4d, regvalue, cur_col, wrap));
 }
 
@@ -1220,21 +1220,6 @@ ahd_clrsint3_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x53, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
-       { "ENLQOTCRC",          0x01, 0x01 },
-       { "ENLQOATNPKT",        0x02, 0x02 },
-       { "ENLQOATNLQ",         0x04, 0x04 },
-       { "ENLQOSTOPT2",        0x08, 0x08 },
-       { "ENLQOTARGSCBPERR",   0x10, 0x10 }
-};
-
-int
-ahd_lqomode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(LQOMODE0_parse_table, 5, "LQOMODE0",
-           0x54, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t LQOSTAT0_parse_table[] = {
        { "LQOTCRC",            0x01, 0x01 },
        { "LQOATNPKT",          0x02, 0x02 },
@@ -1265,6 +1250,36 @@ ahd_clrlqoint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x54, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
+       { "ENLQOTCRC",          0x01, 0x01 },
+       { "ENLQOATNPKT",        0x02, 0x02 },
+       { "ENLQOATNLQ",         0x04, 0x04 },
+       { "ENLQOSTOPT2",        0x08, 0x08 },
+       { "ENLQOTARGSCBPERR",   0x10, 0x10 }
+};
+
+int
+ahd_lqomode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(LQOMODE0_parse_table, 5, "LQOMODE0",
+           0x54, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
+       { "ENLQOPHACHGINPKT",   0x01, 0x01 },
+       { "ENLQOBUSFREE",       0x02, 0x02 },
+       { "ENLQOBADQAS",        0x04, 0x04 },
+       { "ENLQOSTOPI2",        0x08, 0x08 },
+       { "ENLQOINITSCBPERR",   0x10, 0x10 }
+};
+
+int
+ahd_lqomode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(LQOMODE1_parse_table, 5, "LQOMODE1",
+           0x55, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t LQOSTAT1_parse_table[] = {
        { "LQOPHACHGINPKT",     0x01, 0x01 },
        { "LQOBUSFREE",         0x02, 0x02 },
@@ -1295,21 +1310,6 @@ ahd_clrlqoint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x55, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
-       { "ENLQOPHACHGINPKT",   0x01, 0x01 },
-       { "ENLQOBUSFREE",       0x02, 0x02 },
-       { "ENLQOBADQAS",        0x04, 0x04 },
-       { "ENLQOSTOPI2",        0x08, 0x08 },
-       { "ENLQOINITSCBPERR",   0x10, 0x10 }
-};
-
-int
-ahd_lqomode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(LQOMODE1_parse_table, 5, "LQOMODE1",
-           0x55, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t LQOSTAT2_parse_table[] = {
        { "LQOSTOP0",           0x01, 0x01 },
        { "LQOPHACHGOUTPKT",    0x02, 0x02 },
@@ -1594,6 +1594,13 @@ ahd_annexcol_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x65, regvalue, cur_col, wrap));
 }
 
+int
+ahd_annexdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "ANNEXDAT",
+           0x66, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SCSCHKN_parse_table[] = {
        { "LSTSGCLRDIS",        0x01, 0x01 },
        { "SHVALIDSTDIS",       0x02, 0x02 },
@@ -1611,13 +1618,6 @@ ahd_scschkn_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x66, regvalue, cur_col, wrap));
 }
 
-int
-ahd_annexdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(NULL, 0, "ANNEXDAT",
-           0x66, regvalue, cur_col, wrap));
-}
-
 int
 ahd_iownid_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -1728,16 +1728,16 @@ ahd_pll400ctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_pll400cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_unfairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "PLL400CNT0",
+       return (ahd_print_register(NULL, 0, "UNFAIRNESS",
            0x6e, regvalue, cur_col, wrap));
 }
 
 int
-ahd_unfairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_pll400cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "UNFAIRNESS",
+       return (ahd_print_register(NULL, 0, "PLL400CNT0",
            0x6e, regvalue, cur_col, wrap));
 }
 
@@ -1788,30 +1788,30 @@ ahd_hodmaen_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_scbhaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "SGHADDR",
+       return (ahd_print_register(NULL, 0, "SCBHADDR",
            0x7c, regvalue, cur_col, wrap));
 }
 
 int
-ahd_scbhaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "SCBHADDR",
+       return (ahd_print_register(NULL, 0, "SGHADDR",
            0x7c, regvalue, cur_col, wrap));
 }
 
 int
-ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_scbhcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "SGHCNT",
+       return (ahd_print_register(NULL, 0, "SCBHCNT",
            0x84, regvalue, cur_col, wrap));
 }
 
 int
-ahd_scbhcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "SCBHCNT",
+       return (ahd_print_register(NULL, 0, "SGHCNT",
            0x84, regvalue, cur_col, wrap));
 }
 
@@ -1950,25 +1950,25 @@ ahd_nsenable_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x91, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t DCHRXMSG1_parse_table[] = {
+static ahd_reg_parse_entry_t CMCRXMSG1_parse_table[] = {
        { "CBNUM",              0xff, 0xff }
 };
 
 int
-ahd_dchrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_cmcrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(DCHRXMSG1_parse_table, 1, "DCHRXMSG1",
+       return (ahd_print_register(CMCRXMSG1_parse_table, 1, "CMCRXMSG1",
            0x91, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CMCRXMSG1_parse_table[] = {
+static ahd_reg_parse_entry_t DCHRXMSG1_parse_table[] = {
        { "CBNUM",              0xff, 0xff }
 };
 
 int
-ahd_cmcrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dchrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(CMCRXMSG1_parse_table, 1, "CMCRXMSG1",
+       return (ahd_print_register(DCHRXMSG1_parse_table, 1, "DCHRXMSG1",
            0x91, regvalue, cur_col, wrap));
 }
 
@@ -1983,17 +1983,6 @@ ahd_dchrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x92, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYRXMSG2_parse_table[] = {
-       { "MINDEX",             0xff, 0xff }
-};
-
-int
-ahd_ovlyrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(OVLYRXMSG2_parse_table, 1, "OVLYRXMSG2",
-           0x92, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t CMCRXMSG2_parse_table[] = {
        { "MINDEX",             0xff, 0xff }
 };
@@ -2012,6 +2001,17 @@ ahd_ost_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x92, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t OVLYRXMSG2_parse_table[] = {
+       { "MINDEX",             0xff, 0xff }
+};
+
+int
+ahd_ovlyrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(OVLYRXMSG2_parse_table, 1, "OVLYRXMSG2",
+           0x92, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t DCHRXMSG3_parse_table[] = {
        { "MCLASS",             0x0f, 0x0f }
 };
@@ -2023,6 +2023,17 @@ ahd_dchrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x93, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t OVLYRXMSG3_parse_table[] = {
+       { "MCLASS",             0x0f, 0x0f }
+};
+
+int
+ahd_ovlyrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(OVLYRXMSG3_parse_table, 1, "OVLYRXMSG3",
+           0x93, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t CMCRXMSG3_parse_table[] = {
        { "MCLASS",             0x0f, 0x0f }
 };
@@ -2051,17 +2062,6 @@ ahd_pcixctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x93, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYRXMSG3_parse_table[] = {
-       { "MCLASS",             0x0f, 0x0f }
-};
-
-int
-ahd_ovlyrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(OVLYRXMSG3_parse_table, 1, "OVLYRXMSG3",
-           0x93, regvalue, cur_col, wrap));
-}
-
 int
 ahd_ovlyseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -2070,16 +2070,16 @@ ahd_ovlyseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_cmcseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dchseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "CMCSEQBCNT",
+       return (ahd_print_register(NULL, 0, "DCHSEQBCNT",
            0x94, regvalue, cur_col, wrap));
 }
 
 int
-ahd_dchseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_cmcseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "DCHSEQBCNT",
+       return (ahd_print_register(NULL, 0, "CMCSEQBCNT",
            0x94, regvalue, cur_col, wrap));
 }
 
@@ -2101,7 +2101,7 @@ ahd_cmcspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x96, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
+static ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
        { "RXSPLTRSP",          0x01, 0x01 },
        { "RXSCEMSG",           0x02, 0x02 },
        { "RXOVRUN",            0x04, 0x04 },
@@ -2113,13 +2113,13 @@ static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
 };
 
 int
-ahd_ovlyspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dchspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(OVLYSPLTSTAT0_parse_table, 8, "OVLYSPLTSTAT0",
+       return (ahd_print_register(DCHSPLTSTAT0_parse_table, 8, "DCHSPLTSTAT0",
            0x96, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
+static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
        { "RXSPLTRSP",          0x01, 0x01 },
        { "RXSCEMSG",           0x02, 0x02 },
        { "RXOVRUN",            0x04, 0x04 },
@@ -2131,42 +2131,42 @@ static ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
 };
 
 int
-ahd_dchspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ovlyspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(DCHSPLTSTAT0_parse_table, 8, "DCHSPLTSTAT0",
+       return (ahd_print_register(OVLYSPLTSTAT0_parse_table, 8, "OVLYSPLTSTAT0",
            0x96, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
+static ahd_reg_parse_entry_t CMCSPLTSTAT1_parse_table[] = {
        { "RXDATABUCKET",       0x01, 0x01 }
 };
 
 int
-ahd_dchspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_cmcspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(DCHSPLTSTAT1_parse_table, 1, "DCHSPLTSTAT1",
+       return (ahd_print_register(CMCSPLTSTAT1_parse_table, 1, "CMCSPLTSTAT1",
            0x97, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CMCSPLTSTAT1_parse_table[] = {
+static ahd_reg_parse_entry_t OVLYSPLTSTAT1_parse_table[] = {
        { "RXDATABUCKET",       0x01, 0x01 }
 };
 
 int
-ahd_cmcspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ovlyspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(CMCSPLTSTAT1_parse_table, 1, "CMCSPLTSTAT1",
+       return (ahd_print_register(OVLYSPLTSTAT1_parse_table, 1, "OVLYSPLTSTAT1",
            0x97, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t OVLYSPLTSTAT1_parse_table[] = {
+static ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
        { "RXDATABUCKET",       0x01, 0x01 }
 };
 
 int
-ahd_ovlyspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dchspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(OVLYSPLTSTAT1_parse_table, 1, "OVLYSPLTSTAT1",
+       return (ahd_print_register(DCHSPLTSTAT1_parse_table, 1, "DCHSPLTSTAT1",
            0x97, regvalue, cur_col, wrap));
 }
 
@@ -2320,26 +2320,26 @@ ahd_sgspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x9e, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SFUNCT_parse_table[] = {
-       { "TEST_NUM",           0x0f, 0x0f },
-       { "TEST_GROUP",         0xf0, 0xf0 }
+static ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
+       { "RXDATABUCKET",       0x01, 0x01 }
 };
 
 int
-ahd_sfunct_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sgspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(SFUNCT_parse_table, 2, "SFUNCT",
+       return (ahd_print_register(SGSPLTSTAT1_parse_table, 1, "SGSPLTSTAT1",
            0x9f, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
-       { "RXDATABUCKET",       0x01, 0x01 }
+static ahd_reg_parse_entry_t SFUNCT_parse_table[] = {
+       { "TEST_NUM",           0x0f, 0x0f },
+       { "TEST_GROUP",         0xf0, 0xf0 }
 };
 
 int
-ahd_sgspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_sfunct_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(SGSPLTSTAT1_parse_table, 1, "SGSPLTSTAT1",
+       return (ahd_print_register(SFUNCT_parse_table, 2, "SFUNCT",
            0x9f, regvalue, cur_col, wrap));
 }
 
@@ -2537,16 +2537,16 @@ ahd_ccsgaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ccscbadr_bk_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "CCSCBADDR",
+       return (ahd_print_register(NULL, 0, "CCSCBADR_BK",
            0xac, regvalue, cur_col, wrap));
 }
 
 int
-ahd_ccscbadr_bk_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "CCSCBADR_BK",
+       return (ahd_print_register(NULL, 0, "CCSCBADDR",
            0xac, regvalue, cur_col, wrap));
 }
 
@@ -2566,22 +2566,6 @@ ahd_cmc_rambist_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0xad, regvalue, cur_col, wrap));
 }
 
-static ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
-       { "CCSGRESET",          0x01, 0x01 },
-       { "SG_FETCH_REQ",       0x02, 0x02 },
-       { "CCSGENACK",          0x08, 0x08 },
-       { "SG_CACHE_AVAIL",     0x10, 0x10 },
-       { "CCSGDONE",           0x80, 0x80 },
-       { "CCSGEN",             0x0c, 0x0c }
-};
-
-int
-ahd_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(CCSGCTL_parse_table, 6, "CCSGCTL",
-           0xad, regvalue, cur_col, wrap));
-}
-
 static ahd_reg_parse_entry_t CCSCBCTL_parse_table[] = {
        { "CCSCBRESET",         0x01, 0x01 },
        { "CCSCBDIR",           0x04, 0x04 },
@@ -2598,6 +2582,22 @@ ahd_ccscbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0xad, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
+       { "CCSGRESET",          0x01, 0x01 },
+       { "SG_FETCH_REQ",       0x02, 0x02 },
+       { "CCSGENACK",          0x08, 0x08 },
+       { "SG_CACHE_AVAIL",     0x10, 0x10 },
+       { "CCSGDONE",           0x80, 0x80 },
+       { "CCSGEN",             0x0c, 0x0c }
+};
+
+int
+ahd_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(CCSGCTL_parse_table, 6, "CCSGCTL",
+           0xad, regvalue, cur_col, wrap));
+}
+
 int
 ahd_ccsgram_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -2841,30 +2841,30 @@ ahd_wrtbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_dfptrs_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_rcvrbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "DFPTRS",
+       return (ahd_print_register(NULL, 0, "RCVRBIASCALC",
            0xc8, regvalue, cur_col, wrap));
 }
 
 int
-ahd_rcvrbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dfptrs_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "RCVRBIASCALC",
+       return (ahd_print_register(NULL, 0, "DFPTRS",
            0xc8, regvalue, cur_col, wrap));
 }
 
 int
-ahd_dfbkptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_skewcalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "DFBKPTR",
+       return (ahd_print_register(NULL, 0, "SKEWCALC",
            0xc9, regvalue, cur_col, wrap));
 }
 
 int
-ahd_skewcalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_dfbkptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "SKEWCALC",
+       return (ahd_print_register(NULL, 0, "DFBKPTR",
            0xc9, regvalue, cur_col, wrap));
 }
 
@@ -3001,6 +3001,13 @@ ahd_dindex_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0xe4, regvalue, cur_col, wrap));
 }
 
+int
+ahd_brkaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "BRKADDR0",
+           0xe6, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t BRKADDR1_parse_table[] = {
        { "BRKDIS",             0x80, 0x80 }
 };
@@ -3012,13 +3019,6 @@ ahd_brkaddr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0xe6, regvalue, cur_col, wrap));
 }
 
-int
-ahd_brkaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-       return (ahd_print_register(NULL, 0, "BRKADDR0",
-           0xe6, regvalue, cur_col, wrap));
-}
-
 int
 ahd_allones_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
@@ -3069,30 +3069,30 @@ ahd_stack_print(u_int regvalue, u_int *cur_col, u_int wrap)
 }
 
 int
-ahd_curaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_intvec1_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "CURADDR",
+       return (ahd_print_register(NULL, 0, "INTVEC1_ADDR",
            0xf4, regvalue, cur_col, wrap));
 }
 
 int
-ahd_intvec1_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_curaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "INTVEC1_ADDR",
+       return (ahd_print_register(NULL, 0, "CURADDR",
            0xf4, regvalue, cur_col, wrap));
 }
 
 int
-ahd_intvec2_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_lastaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "INTVEC2_ADDR",
+       return (ahd_print_register(NULL, 0, "LASTADDR",
            0xf6, regvalue, cur_col, wrap));
 }
 
 int
-ahd_lastaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_intvec2_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "LASTADDR",
+       return (ahd_print_register(NULL, 0, "INTVEC2_ADDR",
            0xf6, regvalue, cur_col, wrap));
 }
 
@@ -3173,25 +3173,46 @@ ahd_complete_dma_scb_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
            0x12c, regvalue, cur_col, wrap));
 }
 
+int
+ahd_complete_dma_scb_tail_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_TAIL",
+           0x12e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_complete_on_qfreeze_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "COMPLETE_ON_QFREEZE_HEAD",
+           0x130, regvalue, cur_col, wrap));
+}
+
 int
 ahd_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "QFREEZE_COUNT",
-           0x12e, regvalue, cur_col, wrap));
+           0x132, regvalue, cur_col, wrap));
+}
+
+int
+ahd_kernel_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+       return (ahd_print_register(NULL, 0, "KERNEL_QFREEZE_COUNT",
+           0x134, regvalue, cur_col, wrap));
 }
 
 int
 ahd_saved_mode_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "SAVED_MODE",
-           0x130, regvalue, cur_col, wrap));
+           0x136, regvalue, cur_col, wrap));
 }
 
 int
 ahd_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "MSG_OUT",
-           0x131, regvalue, cur_col, wrap));
+           0x137, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t DMAPARAMS_parse_table[] = {
@@ -3211,7 +3232,7 @@ int
 ahd_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(DMAPARAMS_parse_table, 10, "DMAPARAMS",
-           0x132, regvalue, cur_col, wrap));
+           0x138, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
@@ -3230,21 +3251,21 @@ int
 ahd_seq_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(SEQ_FLAGS_parse_table, 9, "SEQ_FLAGS",
-           0x133, regvalue, cur_col, wrap));
+           0x139, regvalue, cur_col, wrap));
 }
 
 int
 ahd_saved_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "SAVED_SCSIID",
-           0x134, regvalue, cur_col, wrap));
+           0x13a, regvalue, cur_col, wrap));
 }
 
 int
 ahd_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "SAVED_LUN",
-           0x135, regvalue, cur_col, wrap));
+           0x13b, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t LASTPHASE_parse_table[] = {
@@ -3267,42 +3288,42 @@ int
 ahd_lastphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(LASTPHASE_parse_table, 13, "LASTPHASE",
-           0x136, regvalue, cur_col, wrap));
+           0x13c, regvalue, cur_col, wrap));
 }
 
 int
 ahd_qoutfifo_entry_valid_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG",
-           0x137, regvalue, cur_col, wrap));
+           0x13d, regvalue, cur_col, wrap));
 }
 
 int
-ahd_shared_data_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_kernel_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "SHARED_DATA_ADDR",
-           0x138, regvalue, cur_col, wrap));
+       return (ahd_print_register(NULL, 0, "KERNEL_TQINPOS",
+           0x13e, regvalue, cur_col, wrap));
 }
 
 int
-ahd_qoutfifo_next_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR",
-           0x13c, regvalue, cur_col, wrap));
+       return (ahd_print_register(NULL, 0, "TQINPOS",
+           0x13f, regvalue, cur_col, wrap));
 }
 
 int
-ahd_kernel_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_shared_data_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "KERNEL_TQINPOS",
+       return (ahd_print_register(NULL, 0, "SHARED_DATA_ADDR",
            0x140, regvalue, cur_col, wrap));
 }
 
 int
-ahd_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_qoutfifo_next_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-       return (ahd_print_register(NULL, 0, "TQINPOS",
-           0x141, regvalue, cur_col, wrap));
+       return (ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR",
+           0x144, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t ARG_1_parse_table[] = {
@@ -3320,21 +3341,21 @@ int
 ahd_arg_1_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(ARG_1_parse_table, 8, "ARG_1",
-           0x142, regvalue, cur_col, wrap));
+           0x148, regvalue, cur_col, wrap));
 }
 
 int
 ahd_arg_2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "ARG_2",
-           0x143, regvalue, cur_col, wrap));
+           0x149, regvalue, cur_col, wrap));
 }
 
 int
 ahd_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "LAST_MSG",
-           0x144, regvalue, cur_col, wrap));
+           0x14a, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
@@ -3350,14 +3371,14 @@ int
 ahd_scsiseq_template_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(SCSISEQ_TEMPLATE_parse_table, 6, "SCSISEQ_TEMPLATE",
-           0x145, regvalue, cur_col, wrap));
+           0x14b, regvalue, cur_col, wrap));
 }
 
 int
 ahd_initiator_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "INITIATOR_TAG",
-           0x146, regvalue, cur_col, wrap));
+           0x14c, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
@@ -3369,63 +3390,63 @@ int
 ahd_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(SEQ_FLAGS2_parse_table, 2, "SEQ_FLAGS2",
-           0x147, regvalue, cur_col, wrap));
+           0x14d, regvalue, cur_col, wrap));
 }
 
 int
 ahd_allocfifo_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR",
-           0x148, regvalue, cur_col, wrap));
+           0x14e, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "INT_COALESCING_TIMER",
-           0x14a, regvalue, cur_col, wrap));
+           0x150, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS",
-           0x14c, regvalue, cur_col, wrap));
+           0x152, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS",
-           0x14d, regvalue, cur_col, wrap));
+           0x153, regvalue, cur_col, wrap));
 }
 
 int
 ahd_cmds_pending_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "CMDS_PENDING",
-           0x14e, regvalue, cur_col, wrap));
+           0x154, regvalue, cur_col, wrap));
 }
 
 int
 ahd_int_coalescing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT",
-           0x150, regvalue, cur_col, wrap));
+           0x156, regvalue, cur_col, wrap));
 }
 
 int
 ahd_local_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX",
-           0x151, regvalue, cur_col, wrap));
+           0x157, regvalue, cur_col, wrap));
 }
 
 int
 ahd_cmdsize_table_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
        return (ahd_print_register(NULL, 0, "CMDSIZE_TABLE",
-           0x152, regvalue, cur_col, wrap));
+           0x158, regvalue, cur_col, wrap));
 }
 
 int
index 77c471f934e0665da99c75622627528be86d527f..b1e5365be23005f11957da625356bd7c0f147c20 100644 (file)
  * DO NOT EDIT - This file is automatically generated
  *              from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#119 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#76 $
  */
 static uint8_t seqprog[] = {
        0xff, 0x02, 0x06, 0x78,
-       0x00, 0xea, 0x50, 0x59,
+       0x00, 0xea, 0x64, 0x59,
        0x01, 0xea, 0x04, 0x30,
        0xff, 0x04, 0x0c, 0x78,
-       0x19, 0xea, 0x50, 0x59,
+       0x19, 0xea, 0x64, 0x59,
        0x19, 0xea, 0x04, 0x00,
-       0x33, 0xea, 0x44, 0x59,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x60, 0x3a, 0x1a, 0x68,
-       0x04, 0x47, 0x1b, 0x68,
-       0xff, 0x21, 0x1b, 0x70,
-       0x40, 0x4b, 0x92, 0x69,
-       0x00, 0xe2, 0x54, 0x59,
-       0x40, 0x4b, 0x92, 0x69,
-       0x20, 0x4b, 0x82, 0x69,
-       0xfc, 0x42, 0x24, 0x78,
-       0x10, 0x40, 0x24, 0x78,
-       0x00, 0xe2, 0xc4, 0x5d,
-       0x20, 0x4d, 0x28, 0x78,
-       0x00, 0xe2, 0xc4, 0x5d,
+       0x60, 0x3a, 0x3a, 0x68,
+       0x04, 0x4d, 0x35, 0x78,
+       0x01, 0x34, 0xc1, 0x31,
+       0x00, 0x32, 0x21, 0x60,
+       0x01, 0x35, 0xc1, 0x31,
+       0x00, 0x33, 0x21, 0x60,
+       0xfb, 0x4d, 0x9b, 0x0a,
+       0x00, 0xe2, 0x34, 0x40,
+       0x50, 0x4b, 0x3a, 0x68,
+       0xff, 0x31, 0x3b, 0x70,
+       0x02, 0x30, 0x51, 0x31,
+       0xff, 0x8d, 0x2d, 0x70,
+       0x02, 0x8c, 0x51, 0x31,
+       0xff, 0x8d, 0x29, 0x60,
+       0x02, 0x28, 0x19, 0x33,
+       0x02, 0x30, 0x51, 0x32,
+       0xff, 0xea, 0x62, 0x02,
+       0x00, 0xe2, 0x3a, 0x40,
+       0xff, 0x21, 0x3b, 0x70,
+       0x40, 0x4b, 0xaa, 0x69,
+       0x00, 0xe2, 0x68, 0x59,
+       0x40, 0x4b, 0xaa, 0x69,
+       0x20, 0x4b, 0x96, 0x69,
+       0xfc, 0x42, 0x44, 0x78,
+       0x10, 0x40, 0x44, 0x78,
+       0x00, 0xe2, 0xfc, 0x5d,
+       0x20, 0x4d, 0x48, 0x78,
+       0x00, 0xe2, 0xfc, 0x5d,
        0x30, 0x3f, 0xc0, 0x09,
-       0x30, 0xe0, 0x30, 0x60,
+       0x30, 0xe0, 0x50, 0x60,
        0x7f, 0x4a, 0x94, 0x08,
-       0x00, 0xe2, 0x32, 0x40,
+       0x00, 0xe2, 0x52, 0x40,
        0xc0, 0x4a, 0x94, 0x00,
-       0x00, 0xe2, 0x3e, 0x58,
-       0x00, 0xe2, 0x56, 0x58,
-       0x00, 0xe2, 0x66, 0x58,
+       0x00, 0xe2, 0x5e, 0x58,
+       0x00, 0xe2, 0x76, 0x58,
+       0x00, 0xe2, 0x86, 0x58,
        0x00, 0xe2, 0x06, 0x40,
-       0x33, 0xea, 0x44, 0x59,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x01, 0x52, 0x64, 0x78,
+       0x01, 0x52, 0x84, 0x78,
        0x02, 0x58, 0x50, 0x31,
        0xff, 0xea, 0x10, 0x0b,
-       0xff, 0x97, 0x4f, 0x78,
-       0x50, 0x4b, 0x4a, 0x68,
+       0xff, 0x97, 0x6f, 0x78,
+       0x50, 0x4b, 0x6a, 0x68,
        0xbf, 0x3a, 0x74, 0x08,
-       0x14, 0xea, 0x50, 0x59,
+       0x14, 0xea, 0x64, 0x59,
        0x14, 0xea, 0x04, 0x00,
        0x08, 0x92, 0x25, 0x03,
-       0xff, 0x90, 0x3f, 0x68,
-       0x00, 0xe2, 0x56, 0x5b,
-       0x00, 0xe2, 0x3e, 0x40,
-       0x00, 0xea, 0x44, 0x59,
+       0xff, 0x90, 0x5f, 0x68,
+       0x00, 0xe2, 0x76, 0x5b,
+       0x00, 0xe2, 0x5e, 0x40,
+       0x00, 0xea, 0x5e, 0x59,
        0x01, 0xea, 0x00, 0x30,
-       0x80, 0xf9, 0x5e, 0x68,
-       0x00, 0xe2, 0x42, 0x59,
-       0x11, 0xea, 0x44, 0x59,
+       0x80, 0xf9, 0x7e, 0x68,
+       0x00, 0xe2, 0x5c, 0x59,
+       0x11, 0xea, 0x5e, 0x59,
        0x11, 0xea, 0x00, 0x00,
-       0x80, 0xf9, 0x42, 0x79,
+       0x80, 0xf9, 0x5c, 0x79,
        0xff, 0xea, 0xd4, 0x0d,
-       0x22, 0xea, 0x44, 0x59,
+       0x22, 0xea, 0x5e, 0x59,
        0x22, 0xea, 0x00, 0x00,
-       0x10, 0x16, 0x70, 0x78,
-       0x01, 0x0b, 0xa2, 0x32,
+       0x10, 0x16, 0x90, 0x78,
        0x10, 0x16, 0x2c, 0x00,
-       0x18, 0xad, 0x00, 0x79,
-       0x04, 0xad, 0xca, 0x68,
-       0x80, 0xad, 0x64, 0x78,
-       0x10, 0xad, 0x98, 0x78,
-       0xff, 0x88, 0x83, 0x68,
+       0x01, 0x0b, 0xae, 0x32,
+       0x18, 0xad, 0x12, 0x79,
+       0x04, 0xad, 0xdc, 0x68,
+       0x80, 0xad, 0x84, 0x78,
+       0x10, 0xad, 0xaa, 0x78,
        0xe7, 0xad, 0x5a, 0x09,
        0x02, 0x8c, 0x59, 0x32,
+       0xff, 0x8d, 0xa1, 0x60,
+       0xff, 0xea, 0x5e, 0x02,
+       0xff, 0x88, 0xa7, 0x78,
+       0x02, 0x30, 0x19, 0x33,
+       0x02, 0xa8, 0x60, 0x36,
        0x02, 0x28, 0x19, 0x33,
        0x02, 0xa8, 0x50, 0x36,
-       0x33, 0xea, 0x44, 0x59,
-       0x33, 0xea, 0x00, 0x00,
-       0x40, 0x3a, 0x64, 0x68,
-       0x50, 0x4b, 0x64, 0x68,
-       0x22, 0xea, 0x44, 0x59,
-       0x22, 0xea, 0x00, 0x00,
-       0xe7, 0xad, 0x5a, 0x09,
-       0x02, 0x8c, 0x59, 0x32,
-       0x1a, 0xea, 0x50, 0x59,
-       0x1a, 0xea, 0x04, 0x00,
-       0xff, 0xea, 0xd4, 0x0d,
        0xe7, 0xad, 0x5a, 0x09,
-       0x00, 0xe2, 0xa6, 0x58,
+       0x00, 0xe2, 0xb8, 0x58,
        0xff, 0xea, 0x56, 0x02,
-       0x04, 0x7c, 0x78, 0x32,
-       0x20, 0x16, 0x64, 0x78,
-       0x04, 0x38, 0x79, 0x32,
-       0x80, 0x37, 0x6f, 0x16,
-       0xff, 0x2d, 0xb5, 0x60,
-       0xff, 0x29, 0xb5, 0x60,
-       0x40, 0x51, 0xc5, 0x78,
-       0xff, 0x4f, 0xb5, 0x68,
-       0xff, 0x4d, 0xc1, 0x19,
-       0x00, 0x4e, 0xd5, 0x19,
-       0x00, 0xe2, 0xc4, 0x50,
-       0x01, 0x4c, 0xc1, 0x31,
-       0x00, 0x50, 0xd5, 0x19,
-       0x00, 0xe2, 0xc4, 0x48,
-       0x80, 0x18, 0x64, 0x78,
-       0x02, 0x4a, 0x1d, 0x30,
+       0x04, 0x7c, 0x88, 0x32,
+       0x20, 0x16, 0x84, 0x78,
+       0x04, 0x40, 0x89, 0x32,
+       0x80, 0x3d, 0x7b, 0x16,
+       0xff, 0x2d, 0xc7, 0x60,
+       0xff, 0x29, 0xc7, 0x60,
+       0x40, 0x57, 0xd7, 0x78,
+       0xff, 0x55, 0xc7, 0x68,
+       0xff, 0x53, 0xc1, 0x19,
+       0x00, 0x54, 0xd5, 0x19,
+       0x00, 0xe2, 0xd6, 0x50,
+       0x01, 0x52, 0xc1, 0x31,
+       0x00, 0x56, 0xd5, 0x19,
+       0x00, 0xe2, 0xd6, 0x48,
+       0x80, 0x18, 0x84, 0x78,
+       0x02, 0x50, 0x1d, 0x30,
        0x10, 0xea, 0x18, 0x00,
        0x60, 0x18, 0x30, 0x00,
        0x7f, 0x18, 0x30, 0x0c,
        0x02, 0xea, 0x02, 0x00,
-       0xff, 0xea, 0xa0, 0x0a,
+       0xff, 0xea, 0xac, 0x0a,
        0x80, 0x18, 0x30, 0x04,
-       0x40, 0xad, 0x64, 0x78,
+       0x40, 0xad, 0x84, 0x78,
        0xe7, 0xad, 0x5a, 0x09,
        0x02, 0xa8, 0x40, 0x31,
        0xff, 0xea, 0xc0, 0x09,
-       0x01, 0x4e, 0x9d, 0x1a,
-       0x00, 0x4f, 0x9f, 0x22,
+       0x01, 0x54, 0xa9, 0x1a,
+       0x00, 0x55, 0xab, 0x22,
        0x01, 0x94, 0x6d, 0x33,
-       0x01, 0xea, 0x20, 0x33,
+       0xff, 0xea, 0x20, 0x0b,
        0x04, 0xac, 0x49, 0x32,
        0xff, 0xea, 0x5a, 0x03,
        0xff, 0xea, 0x5e, 0x03,
        0x01, 0x10, 0xd4, 0x31,
-       0x10, 0x92, 0xf5, 0x68,
+       0x10, 0x92, 0x07, 0x69,
        0x3d, 0x93, 0xc5, 0x29,
        0xfe, 0xe2, 0xc4, 0x09,
        0x01, 0xea, 0xc6, 0x01,
        0x02, 0xe2, 0xc8, 0x31,
        0x02, 0xec, 0x50, 0x31,
        0x02, 0xa0, 0xda, 0x31,
-       0xff, 0xa9, 0xf4, 0x70,
+       0xff, 0xa9, 0x06, 0x71,
        0x02, 0xa0, 0x58, 0x37,
-       0xff, 0x21, 0xfd, 0x70,
+       0xff, 0x21, 0x0f, 0x71,
        0x02, 0x22, 0x51, 0x31,
        0x02, 0xa0, 0x5c, 0x33,
        0x02, 0xa0, 0x44, 0x36,
        0x02, 0xa0, 0x40, 0x32,
        0x02, 0xa0, 0x44, 0x36,
-       0x04, 0x47, 0x05, 0x69,
-       0x40, 0x16, 0x30, 0x69,
-       0xff, 0x2d, 0x35, 0x61,
-       0xff, 0x29, 0x65, 0x70,
-       0x01, 0x37, 0xc1, 0x31,
+       0x04, 0x4d, 0x17, 0x69,
+       0x40, 0x16, 0x48, 0x69,
+       0xff, 0x2d, 0x4d, 0x61,
+       0xff, 0x29, 0x85, 0x70,
        0x02, 0x28, 0x55, 0x32,
        0x01, 0xea, 0x5a, 0x01,
-       0x04, 0x3c, 0xf9, 0x30,
+       0x04, 0x44, 0xf9, 0x30,
+       0x01, 0x44, 0xc1, 0x31,
        0x02, 0x28, 0x51, 0x31,
-       0x01, 0xa8, 0x60, 0x31,
-       0x00, 0xa9, 0x60, 0x01,
+       0x02, 0xa8, 0x60, 0x31,
+       0x01, 0xa4, 0x61, 0x31,
+       0x01, 0x3d, 0x61, 0x31,
        0x01, 0x14, 0xd4, 0x31,
-       0x01, 0x50, 0xa1, 0x1a,
-       0xff, 0x4e, 0x9d, 0x1a,
-       0xff, 0x4f, 0x9f, 0x22,
-       0xff, 0x8d, 0x29, 0x71,
-       0x80, 0xac, 0x28, 0x71,
-       0x20, 0x16, 0x28, 0x69,
+       0x01, 0x56, 0xad, 0x1a,
+       0xff, 0x54, 0xa9, 0x1a,
+       0xff, 0x55, 0xab, 0x22,
+       0xff, 0x8d, 0x41, 0x71,
+       0x80, 0xac, 0x40, 0x71,
+       0x20, 0x16, 0x40, 0x69,
+       0x00, 0xac, 0xc4, 0x19,
+       0x07, 0xe2, 0x40, 0xf9,
        0x02, 0x8c, 0x51, 0x31,
-       0x00, 0xe2, 0x12, 0x41,
+       0x00, 0xe2, 0x24, 0x41,
        0x01, 0xac, 0x08, 0x31,
        0x09, 0xea, 0x5a, 0x01,
        0x02, 0x8c, 0x51, 0x32,
        0xff, 0xea, 0x1a, 0x07,
        0x04, 0x24, 0xf9, 0x30,
-       0x1d, 0xea, 0x3a, 0x41,
+       0x1d, 0xea, 0x52, 0x41,
        0x02, 0x2c, 0x51, 0x31,
        0x04, 0xa8, 0xf9, 0x30,
-       0x19, 0xea, 0x3a, 0x41,
+       0x19, 0xea, 0x52, 0x41,
        0x06, 0xea, 0x08, 0x81,
        0x01, 0xe2, 0x5a, 0x35,
-       0x02, 0xf2, 0xf0, 0x35,
+       0x02, 0xf2, 0xf0, 0x31,
+       0xff, 0xea, 0xd4, 0x0d,
        0x02, 0xf2, 0xf0, 0x31,
        0x02, 0xf8, 0xe4, 0x35,
        0x80, 0xea, 0xb2, 0x01,
        0x01, 0xe2, 0x00, 0x30,
        0xff, 0xea, 0xb2, 0x0d,
-       0x80, 0xea, 0xb2, 0x01,
-       0x11, 0x00, 0x00, 0x10,
-       0xff, 0xea, 0xb2, 0x0d,
        0x01, 0xe2, 0x04, 0x30,
        0x01, 0xea, 0x04, 0x34,
        0x02, 0x20, 0xbd, 0x30,
        0x02, 0x20, 0xb9, 0x30,
        0x02, 0x20, 0x51, 0x31,
        0x4c, 0x93, 0xd7, 0x28,
-       0x10, 0x92, 0x63, 0x79,
+       0x10, 0x92, 0x77, 0x79,
        0x01, 0x6b, 0xc0, 0x30,
        0x02, 0x64, 0xc8, 0x00,
        0x40, 0x3a, 0x74, 0x04,
-       0x00, 0xe2, 0x56, 0x58,
-       0x33, 0xea, 0x44, 0x59,
+       0x00, 0xe2, 0x76, 0x58,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x30, 0x3f, 0xc0, 0x09,
-       0x30, 0xe0, 0x64, 0x61,
-       0x20, 0x3f, 0x7a, 0x69,
-       0x10, 0x3f, 0x64, 0x79,
+       0x30, 0xe0, 0x78, 0x61,
+       0x20, 0x3f, 0x8e, 0x69,
+       0x10, 0x3f, 0x78, 0x79,
        0x02, 0xea, 0x7e, 0x00,
-       0x00, 0xea, 0x44, 0x59,
+       0x00, 0xea, 0x5e, 0x59,
        0x01, 0xea, 0x00, 0x30,
-       0x02, 0x48, 0x51, 0x35,
+       0x02, 0x4e, 0x51, 0x35,
        0x01, 0xea, 0x7e, 0x00,
-       0x11, 0xea, 0x44, 0x59,
+       0x11, 0xea, 0x5e, 0x59,
        0x11, 0xea, 0x00, 0x00,
-       0x02, 0x48, 0x51, 0x35,
+       0x02, 0x4e, 0x51, 0x35,
+       0xc0, 0x4a, 0x94, 0x00,
+       0x04, 0x41, 0x9c, 0x79,
        0x08, 0xea, 0x98, 0x00,
        0x08, 0x57, 0xae, 0x00,
        0x08, 0x3c, 0x78, 0x00,
-       0xf0, 0x49, 0x68, 0x0a,
+       0xf0, 0x49, 0x74, 0x0a,
        0x0f, 0x67, 0xc0, 0x09,
-       0x00, 0x34, 0x69, 0x02,
+       0x00, 0x3a, 0x75, 0x02,
        0x20, 0xea, 0x96, 0x00,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x40, 0x3a, 0xae, 0x69,
+       0x00, 0xe2, 0x14, 0x42,
+       0xc0, 0x4a, 0x94, 0x00,
+       0x40, 0x3a, 0xc8, 0x69,
        0x02, 0x55, 0x06, 0x68,
-       0x02, 0x56, 0xae, 0x69,
-       0xff, 0x5b, 0xae, 0x61,
+       0x02, 0x56, 0xc8, 0x69,
+       0xff, 0x5b, 0xc8, 0x61,
        0x02, 0x20, 0x51, 0x31,
        0x80, 0xea, 0xb2, 0x01,
        0x44, 0xea, 0x00, 0x00,
@@ -218,237 +231,246 @@ static uint8_t seqprog[] = {
        0x33, 0xea, 0x00, 0x00,
        0xff, 0xea, 0xb2, 0x09,
        0xff, 0xe0, 0xc0, 0x19,
-       0xff, 0xe0, 0xb0, 0x79,
+       0xff, 0xe0, 0xca, 0x79,
        0x02, 0xac, 0x51, 0x31,
-       0x00, 0xe2, 0xa6, 0x41,
+       0x00, 0xe2, 0xc0, 0x41,
        0x02, 0x5e, 0x50, 0x31,
        0x02, 0xa8, 0xb8, 0x30,
        0x02, 0x5c, 0x50, 0x31,
-       0xff, 0xad, 0xc1, 0x71,
+       0xff, 0xad, 0xdb, 0x71,
        0x02, 0xac, 0x41, 0x31,
        0x02, 0x22, 0x51, 0x31,
        0x02, 0xa0, 0x5c, 0x33,
        0x02, 0xa0, 0x44, 0x32,
-       0x00, 0xe2, 0xca, 0x41,
-       0x10, 0x92, 0xcb, 0x69,
+       0x00, 0xe2, 0xe4, 0x41,
+       0x10, 0x92, 0xe5, 0x69,
        0x3d, 0x93, 0xc9, 0x29,
        0x01, 0xe4, 0xc8, 0x01,
        0x01, 0xea, 0xca, 0x01,
        0xff, 0xea, 0xda, 0x01,
        0x02, 0x20, 0x51, 0x31,
        0x02, 0xae, 0x41, 0x32,
-       0xff, 0x21, 0xd3, 0x61,
+       0xff, 0x21, 0xed, 0x61,
        0xff, 0xea, 0x46, 0x02,
        0x02, 0x5c, 0x50, 0x31,
        0x40, 0xea, 0x96, 0x00,
-       0x02, 0x56, 0xcc, 0x6d,
-       0x01, 0x55, 0xcc, 0x6d,
-       0x10, 0x92, 0xdf, 0x79,
-       0x10, 0x40, 0xe8, 0x69,
-       0x01, 0x56, 0xe8, 0x79,
+       0x02, 0x56, 0x04, 0x6e,
+       0x01, 0x55, 0x04, 0x6e,
+       0x10, 0x92, 0xf9, 0x79,
+       0x10, 0x40, 0x02, 0x6a,
+       0x01, 0x56, 0x02, 0x7a,
        0xff, 0x97, 0x07, 0x78,
-       0x13, 0xea, 0x50, 0x59,
+       0x13, 0xea, 0x64, 0x59,
        0x13, 0xea, 0x04, 0x00,
        0x00, 0xe2, 0x06, 0x40,
        0xbf, 0x3a, 0x74, 0x08,
+       0x04, 0x41, 0x08, 0x7a,
        0x08, 0xea, 0x98, 0x00,
        0x08, 0x57, 0xae, 0x00,
-       0x01, 0x93, 0x69, 0x32,
-       0x01, 0x94, 0x6b, 0x32,
-       0x40, 0xea, 0x66, 0x02,
+       0x01, 0x93, 0x75, 0x32,
+       0x01, 0x94, 0x77, 0x32,
+       0x40, 0xea, 0x72, 0x02,
        0x08, 0x3c, 0x78, 0x00,
-       0x80, 0xea, 0x62, 0x02,
-       0x00, 0xe2, 0xb8, 0x5b,
-       0x01, 0x36, 0xc1, 0x31,
-       0x9f, 0xe0, 0x4c, 0x7c,
-       0x80, 0xe0, 0x0c, 0x72,
-       0xa0, 0xe0, 0x44, 0x72,
-       0xc0, 0xe0, 0x3a, 0x72,
-       0xe0, 0xe0, 0x74, 0x72,
-       0x01, 0xea, 0x50, 0x59,
+       0x80, 0xea, 0x6e, 0x02,
+       0x00, 0xe2, 0xe2, 0x5b,
+       0x01, 0x3c, 0xc1, 0x31,
+       0x9f, 0xe0, 0x84, 0x7c,
+       0x80, 0xe0, 0x28, 0x72,
+       0xa0, 0xe0, 0x64, 0x72,
+       0xc0, 0xe0, 0x5a, 0x72,
+       0xe0, 0xe0, 0x94, 0x72,
+       0x01, 0xea, 0x64, 0x59,
        0x01, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x80, 0x33, 0x13, 0x7a,
-       0x03, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0x14, 0x42,
+       0x80, 0x39, 0x2f, 0x7a,
+       0x03, 0xea, 0x64, 0x59,
        0x03, 0xea, 0x04, 0x00,
-       0xee, 0x00, 0x1a, 0x6a,
+       0xee, 0x00, 0x36, 0x6a,
        0x05, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x44, 0x59,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x02, 0xa8, 0x90, 0x32,
-       0x00, 0xe2, 0x6a, 0x59,
+       0x02, 0xa8, 0x9c, 0x32,
+       0x00, 0xe2, 0x7e, 0x59,
        0xef, 0x96, 0xd5, 0x19,
-       0x00, 0xe2, 0x2a, 0x52,
+       0x00, 0xe2, 0x46, 0x52,
        0x09, 0x80, 0xe1, 0x30,
        0x02, 0xea, 0x36, 0x00,
        0xa8, 0xea, 0x32, 0x00,
-       0x00, 0xe2, 0x30, 0x42,
+       0x00, 0xe2, 0x4c, 0x42,
        0x01, 0x96, 0xd1, 0x30,
        0x10, 0x80, 0x89, 0x31,
        0x20, 0xea, 0x32, 0x00,
-       0xbf, 0x33, 0x67, 0x0a,
-       0x20, 0x19, 0x32, 0x6a,
-       0x02, 0x4d, 0xf8, 0x69,
-       0x40, 0x33, 0x67, 0x02,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x80, 0x33, 0xb5, 0x6a,
+       0xbf, 0x39, 0x73, 0x0a,
+       0x10, 0x4c, 0x56, 0x6a,
+       0x20, 0x19, 0x4e, 0x6a,
+       0x20, 0x19, 0x52, 0x6a,
+       0x02, 0x4d, 0x14, 0x6a,
+       0x40, 0x39, 0x73, 0x02,
+       0x00, 0xe2, 0x14, 0x42,
+       0x80, 0x39, 0xd5, 0x6a,
        0x01, 0x44, 0x10, 0x33,
        0x08, 0x92, 0x25, 0x03,
-       0x00, 0xe2, 0xf8, 0x41,
+       0x00, 0xe2, 0x14, 0x42,
        0x10, 0xea, 0x80, 0x00,
-       0x01, 0x31, 0xc5, 0x31,
-       0x80, 0xe2, 0x60, 0x62,
-       0x10, 0x92, 0x85, 0x6a,
+       0x01, 0x37, 0xc5, 0x31,
+       0x80, 0xe2, 0x80, 0x62,
+       0x10, 0x92, 0xa5, 0x6a,
        0xc0, 0x94, 0xc5, 0x01,
-       0x40, 0x92, 0x51, 0x6a,
+       0x40, 0x92, 0x71, 0x6a,
        0xbf, 0xe2, 0xc4, 0x09,
-       0x20, 0x92, 0x65, 0x7a,
+       0x20, 0x92, 0x85, 0x7a,
        0x01, 0xe2, 0x88, 0x30,
-       0x00, 0xe2, 0xb8, 0x5b,
-       0xa0, 0x36, 0x6d, 0x62,
+       0x00, 0xe2, 0xe2, 0x5b,
+       0xa0, 0x3c, 0x8d, 0x62,
        0x23, 0x92, 0x89, 0x08,
-       0x00, 0xe2, 0xb8, 0x5b,
-       0xa0, 0x36, 0x6d, 0x62,
-       0x00, 0xa8, 0x64, 0x42,
-       0xff, 0xe2, 0x64, 0x62,
-       0x00, 0xe2, 0x84, 0x42,
+       0x00, 0xe2, 0xe2, 0x5b,
+       0xa0, 0x3c, 0x8d, 0x62,
+       0x00, 0xa8, 0x84, 0x42,
+       0xff, 0xe2, 0x84, 0x62,
+       0x00, 0xe2, 0xa4, 0x42,
        0x40, 0xea, 0x98, 0x00,
        0x01, 0xe2, 0x88, 0x30,
-       0x00, 0xe2, 0xb8, 0x5b,
-       0xa0, 0x36, 0x43, 0x72,
+       0x00, 0xe2, 0xe2, 0x5b,
+       0xa0, 0x3c, 0x63, 0x72,
        0x40, 0xea, 0x98, 0x00,
-       0x01, 0x31, 0x89, 0x32,
-       0x08, 0xea, 0x62, 0x02,
-       0x00, 0xe2, 0xf8, 0x41,
-       0xe0, 0xea, 0xd4, 0x5b,
-       0x80, 0xe0, 0xc0, 0x6a,
-       0x04, 0xe0, 0x66, 0x73,
-       0x02, 0xe0, 0x96, 0x73,
-       0x00, 0xea, 0x1e, 0x73,
-       0x03, 0xe0, 0xa6, 0x73,
-       0x23, 0xe0, 0x96, 0x72,
-       0x08, 0xe0, 0xbc, 0x72,
-       0x00, 0xe2, 0xb8, 0x5b,
-       0x07, 0xea, 0x50, 0x59,
+       0x01, 0x37, 0x95, 0x32,
+       0x08, 0xea, 0x6e, 0x02,
+       0x00, 0xe2, 0x14, 0x42,
+       0xe0, 0xea, 0xfe, 0x5b,
+       0x80, 0xe0, 0xe0, 0x6a,
+       0x04, 0xe0, 0x92, 0x73,
+       0x02, 0xe0, 0xc4, 0x73,
+       0x00, 0xea, 0x3e, 0x73,
+       0x03, 0xe0, 0xd4, 0x73,
+       0x23, 0xe0, 0xb6, 0x72,
+       0x08, 0xe0, 0xdc, 0x72,
+       0x00, 0xe2, 0xe2, 0x5b,
+       0x07, 0xea, 0x64, 0x59,
        0x07, 0xea, 0x04, 0x00,
-       0x08, 0x42, 0xf9, 0x71,
-       0x04, 0x42, 0x93, 0x62,
-       0x01, 0x43, 0x89, 0x30,
-       0x00, 0xe2, 0x84, 0x42,
+       0x08, 0x48, 0x15, 0x72,
+       0x04, 0x48, 0xb3, 0x62,
+       0x01, 0x49, 0x89, 0x30,
+       0x00, 0xe2, 0xa4, 0x42,
        0x01, 0x44, 0xd4, 0x31,
-       0x00, 0xe2, 0x84, 0x42,
-       0x01, 0x00, 0x60, 0x32,
-       0x33, 0xea, 0x44, 0x59,
+       0x00, 0xe2, 0xa4, 0x42,
+       0x01, 0x00, 0x6c, 0x32,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x4c, 0x34, 0xc1, 0x28,
+       0x4c, 0x3a, 0xc1, 0x28,
        0x01, 0x64, 0xc0, 0x31,
-       0x00, 0x30, 0x45, 0x59,
-       0x01, 0x30, 0x01, 0x30,
-       0x01, 0xe0, 0xba, 0x7a,
-       0xa0, 0xea, 0xca, 0x5b,
-       0x01, 0xa0, 0xba, 0x62,
-       0x01, 0x84, 0xaf, 0x7a,
-       0x01, 0x95, 0xbd, 0x6a,
-       0x05, 0xea, 0x50, 0x59,
+       0x00, 0x36, 0x5f, 0x59,
+       0x01, 0x36, 0x01, 0x30,
+       0x01, 0xe0, 0xda, 0x7a,
+       0xa0, 0xea, 0xf4, 0x5b,
+       0x01, 0xa0, 0xda, 0x62,
+       0x01, 0x84, 0xcf, 0x7a,
+       0x01, 0x95, 0xdd, 0x6a,
+       0x05, 0xea, 0x64, 0x59,
        0x05, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xbc, 0x42,
-       0x03, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0xdc, 0x42,
+       0x03, 0xea, 0x64, 0x59,
        0x03, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xbc, 0x42,
-       0x07, 0xea, 0xdc, 0x5b,
+       0x00, 0xe2, 0xdc, 0x42,
+       0x07, 0xea, 0x06, 0x5c,
        0x01, 0x44, 0xd4, 0x31,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x3f, 0xe0, 0x6a, 0x0a,
-       0xc0, 0x34, 0xc1, 0x09,
-       0x00, 0x35, 0x51, 0x01,
+       0x00, 0xe2, 0x14, 0x42,
+       0x3f, 0xe0, 0x76, 0x0a,
+       0xc0, 0x3a, 0xc1, 0x09,
+       0x00, 0x3b, 0x51, 0x01,
        0xff, 0xea, 0x52, 0x09,
-       0x30, 0x34, 0xc5, 0x09,
+       0x30, 0x3a, 0xc5, 0x09,
        0x3d, 0xe2, 0xc4, 0x29,
        0xb8, 0xe2, 0xc4, 0x19,
        0x01, 0xea, 0xc6, 0x01,
        0x02, 0xe2, 0xc8, 0x31,
        0x02, 0xec, 0x40, 0x31,
-       0xff, 0xa1, 0xdc, 0x72,
+       0xff, 0xa1, 0xfc, 0x72,
        0x02, 0xe8, 0xda, 0x31,
        0x02, 0xa0, 0x50, 0x31,
-       0x00, 0xe2, 0xfe, 0x42,
-       0x80, 0x33, 0x67, 0x02,
+       0x00, 0xe2, 0x1e, 0x43,
+       0x80, 0x39, 0x73, 0x02,
        0x01, 0x44, 0xd4, 0x31,
-       0x00, 0xe2, 0xb8, 0x5b,
-       0x01, 0x33, 0x67, 0x02,
-       0xe0, 0x36, 0x19, 0x63,
-       0x02, 0x33, 0x67, 0x02,
-       0x20, 0x46, 0x12, 0x63,
+       0x00, 0xe2, 0xe2, 0x5b,
+       0x01, 0x39, 0x73, 0x02,
+       0xe0, 0x3c, 0x39, 0x63,
+       0x02, 0x39, 0x73, 0x02,
+       0x20, 0x46, 0x32, 0x63,
        0xff, 0xea, 0x52, 0x09,
-       0xa8, 0xea, 0xca, 0x5b,
-       0x04, 0x92, 0xf9, 0x7a,
-       0x01, 0x34, 0xc1, 0x31,
-       0x00, 0x93, 0xf9, 0x62,
-       0x01, 0x35, 0xc1, 0x31,
-       0x00, 0x94, 0x03, 0x73,
+       0xa8, 0xea, 0xf4, 0x5b,
+       0x04, 0x92, 0x19, 0x7b,
+       0x01, 0x3a, 0xc1, 0x31,
+       0x00, 0x93, 0x19, 0x63,
+       0x01, 0x3b, 0xc1, 0x31,
+       0x00, 0x94, 0x23, 0x73,
        0x01, 0xa9, 0x52, 0x11,
-       0xff, 0xa9, 0xee, 0x6a,
-       0x00, 0xe2, 0x12, 0x43,
-       0x10, 0x33, 0x67, 0x02,
-       0x04, 0x92, 0x13, 0x7b,
+       0xff, 0xa9, 0x0e, 0x6b,
+       0x00, 0xe2, 0x32, 0x43,
+       0x10, 0x39, 0x73, 0x02,
+       0x04, 0x92, 0x33, 0x7b,
        0xfb, 0x92, 0x25, 0x0b,
-       0xff, 0xea, 0x66, 0x0a,
-       0x01, 0xa4, 0x0d, 0x6b,
-       0x02, 0xa8, 0x90, 0x32,
-       0x00, 0xe2, 0x6a, 0x59,
-       0x10, 0x92, 0xbd, 0x7a,
-       0xff, 0xea, 0xdc, 0x5b,
-       0x00, 0xe2, 0xbc, 0x42,
-       0x04, 0xea, 0x50, 0x59,
+       0xff, 0xea, 0x72, 0x0a,
+       0x01, 0xa4, 0x2d, 0x6b,
+       0x02, 0xa8, 0x9c, 0x32,
+       0x00, 0xe2, 0x7e, 0x59,
+       0x10, 0x92, 0xdd, 0x7a,
+       0xff, 0xea, 0x06, 0x5c,
+       0x00, 0xe2, 0xdc, 0x42,
+       0x04, 0xea, 0x64, 0x59,
        0x04, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xbc, 0x42,
-       0x04, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0xdc, 0x42,
+       0x04, 0xea, 0x64, 0x59,
        0x04, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x08, 0x92, 0xb5, 0x7a,
-       0xc0, 0x33, 0x29, 0x7b,
-       0x80, 0x33, 0xb5, 0x6a,
-       0xff, 0x88, 0x29, 0x6b,
-       0x40, 0x33, 0xb5, 0x6a,
-       0x10, 0x92, 0x2f, 0x7b,
-       0x0a, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0x14, 0x42,
+       0x08, 0x92, 0xd5, 0x7a,
+       0xc0, 0x39, 0x49, 0x7b,
+       0x80, 0x39, 0xd5, 0x6a,
+       0xff, 0x88, 0x49, 0x6b,
+       0x40, 0x39, 0xd5, 0x6a,
+       0x10, 0x92, 0x4f, 0x7b,
+       0x0a, 0xea, 0x64, 0x59,
        0x0a, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x4e, 0x5b,
-       0x00, 0xe2, 0x82, 0x43,
-       0x50, 0x4b, 0x36, 0x6b,
+       0x00, 0xe2, 0x6e, 0x5b,
+       0x00, 0xe2, 0xae, 0x43,
+       0x50, 0x4b, 0x56, 0x6b,
        0xbf, 0x3a, 0x74, 0x08,
        0x01, 0xe0, 0xf4, 0x31,
        0xff, 0xea, 0xc0, 0x09,
-       0x01, 0x2e, 0x5d, 0x1a,
-       0x00, 0x2f, 0x5f, 0x22,
-       0x04, 0x47, 0x8f, 0x02,
+       0x01, 0x32, 0x65, 0x1a,
+       0x00, 0x33, 0x67, 0x22,
+       0x04, 0x4d, 0x9b, 0x02,
        0x01, 0xfa, 0xc0, 0x35,
-       0x02, 0xa8, 0x84, 0x32,
+       0x02, 0xa8, 0x90, 0x32,
        0x02, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x44, 0x59,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x02, 0x42, 0x51, 0x31,
-       0xff, 0x90, 0x65, 0x68,
-       0xff, 0x88, 0x5b, 0x6b,
-       0x01, 0xa4, 0x57, 0x6b,
-       0x02, 0xa4, 0x5f, 0x6b,
-       0x01, 0x84, 0x5f, 0x7b,
+       0x02, 0x48, 0x51, 0x31,
+       0xff, 0x90, 0x85, 0x68,
+       0xff, 0x88, 0x7b, 0x6b,
+       0x01, 0xa4, 0x77, 0x6b,
+       0x02, 0xa4, 0x7f, 0x6b,
+       0x01, 0x84, 0x7f, 0x7b,
        0x02, 0x28, 0x19, 0x33,
        0x02, 0xa8, 0x50, 0x36,
-       0xff, 0x88, 0x5f, 0x73,
-       0x00, 0xe2, 0x32, 0x5b,
+       0xff, 0x88, 0x7f, 0x73,
+       0x00, 0xe2, 0x52, 0x5b,
        0x02, 0xa8, 0x20, 0x33,
-       0x02, 0x2c, 0x19, 0x33,
+       0x04, 0xa4, 0x49, 0x03,
+       0xff, 0xea, 0x1a, 0x03,
+       0xff, 0x2d, 0x8b, 0x63,
        0x02, 0xa8, 0x58, 0x32,
-       0x04, 0xa4, 0x49, 0x07,
-       0xc0, 0x33, 0xb5, 0x6a,
+       0x02, 0xa8, 0x5c, 0x36,
+       0x02, 0xa8, 0x40, 0x31,
+       0x02, 0x2e, 0x51, 0x31,
+       0x02, 0xa0, 0x18, 0x33,
+       0x02, 0xa0, 0x5c, 0x36,
+       0xc0, 0x39, 0xd5, 0x6a,
        0x04, 0x92, 0x25, 0x03,
-       0x20, 0x92, 0x83, 0x6b,
+       0x20, 0x92, 0xaf, 0x6b,
        0x02, 0xa8, 0x40, 0x31,
-       0xc0, 0x34, 0xc1, 0x09,
-       0x00, 0x35, 0x51, 0x01,
+       0xc0, 0x3a, 0xc1, 0x09,
+       0x00, 0x3b, 0x51, 0x01,
        0xff, 0xea, 0x52, 0x09,
-       0x30, 0x34, 0xc5, 0x09,
+       0x30, 0x3a, 0xc5, 0x09,
        0x3d, 0xe2, 0xc4, 0x29,
        0xb8, 0xe2, 0xc4, 0x19,
        0x01, 0xea, 0xc6, 0x01,
@@ -458,69 +480,75 @@ static uint8_t seqprog[] = {
        0xf7, 0x57, 0xae, 0x08,
        0x08, 0xea, 0x98, 0x00,
        0x01, 0x44, 0xd4, 0x31,
-       0xee, 0x00, 0x8c, 0x6b,
+       0xee, 0x00, 0xb8, 0x6b,
        0x02, 0xea, 0xb4, 0x00,
-       0x00, 0xe2, 0xb4, 0x5b,
-       0x09, 0x4c, 0x8e, 0x7b,
+       0xc0, 0xea, 0x72, 0x02,
+       0x09, 0x4c, 0xba, 0x7b,
+       0x01, 0xea, 0x78, 0x02,
        0x08, 0x4c, 0x06, 0x68,
-       0x0b, 0xea, 0x50, 0x59,
+       0x0b, 0xea, 0x64, 0x59,
        0x0b, 0xea, 0x04, 0x00,
        0x01, 0x44, 0xd4, 0x31,
-       0x20, 0x33, 0xf9, 0x79,
-       0x00, 0xe2, 0x9e, 0x5b,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x01, 0x84, 0xa3, 0x7b,
+       0x20, 0x39, 0x15, 0x7a,
+       0x00, 0xe2, 0xcc, 0x5b,
+       0x00, 0xe2, 0x14, 0x42,
+       0x01, 0x84, 0xd1, 0x7b,
        0x01, 0xa4, 0x49, 0x07,
        0x08, 0x60, 0x30, 0x33,
        0x08, 0x80, 0x41, 0x37,
-       0xdf, 0x33, 0x67, 0x0a,
-       0xee, 0x00, 0xb0, 0x6b,
+       0xdf, 0x39, 0x73, 0x0a,
+       0xee, 0x00, 0xde, 0x6b,
        0x05, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x44, 0x59,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
-       0x00, 0xe2, 0x6a, 0x59,
-       0x00, 0xe2, 0xbc, 0x42,
-       0x01, 0xea, 0x6c, 0x02,
-       0xc0, 0xea, 0x66, 0x06,
-       0xff, 0x42, 0xc4, 0x6b,
-       0x01, 0x41, 0xb8, 0x6b,
-       0x02, 0x41, 0xb8, 0x7b,
-       0xff, 0x42, 0xc4, 0x6b,
-       0x01, 0x41, 0xb8, 0x6b,
-       0x02, 0x41, 0xb8, 0x7b,
-       0xff, 0x42, 0xc4, 0x7b,
-       0x04, 0x4c, 0xb8, 0x6b,
-       0xe0, 0x41, 0x6c, 0x0e,
+       0x00, 0xe2, 0x7e, 0x59,
+       0x00, 0xe2, 0xdc, 0x42,
+       0xff, 0x42, 0xee, 0x6b,
+       0x01, 0x41, 0xe2, 0x6b,
+       0x02, 0x41, 0xe2, 0x7b,
+       0xff, 0x42, 0xee, 0x6b,
+       0x01, 0x41, 0xe2, 0x6b,
+       0x02, 0x41, 0xe2, 0x7b,
+       0xff, 0x42, 0xee, 0x7b,
+       0x04, 0x4c, 0xe2, 0x6b,
+       0xe0, 0x41, 0x78, 0x0e,
        0x01, 0x44, 0xd4, 0x31,
-       0xff, 0x42, 0xcc, 0x7b,
-       0x04, 0x4c, 0xcc, 0x6b,
-       0xe0, 0x41, 0x6c, 0x0a,
-       0xe0, 0x36, 0xf9, 0x61,
+       0xff, 0x42, 0xf6, 0x7b,
+       0x04, 0x4c, 0xf6, 0x6b,
+       0xe0, 0x41, 0x78, 0x0a,
+       0xe0, 0x3c, 0x15, 0x62,
        0xff, 0xea, 0xca, 0x09,
        0x01, 0xe2, 0xc8, 0x31,
        0x01, 0x46, 0xda, 0x35,
        0x01, 0x44, 0xd4, 0x35,
        0x10, 0xea, 0x80, 0x00,
-       0x01, 0xe2, 0x62, 0x36,
-       0x04, 0xa6, 0xe4, 0x7b,
+       0x01, 0xe2, 0x6e, 0x36,
+       0x04, 0xa6, 0x0e, 0x7c,
        0xff, 0xea, 0x5a, 0x09,
        0xff, 0xea, 0x4c, 0x0d,
-       0x01, 0xa6, 0x02, 0x6c,
-       0x10, 0xad, 0x64, 0x78,
-       0x80, 0xad, 0xfa, 0x6b,
-       0x08, 0xad, 0x64, 0x68,
+       0x01, 0xa6, 0x3a, 0x6c,
+       0x10, 0xad, 0x84, 0x78,
+       0x80, 0xad, 0x32, 0x6c,
+       0x08, 0xad, 0x84, 0x68,
+       0x20, 0x19, 0x26, 0x7c,
+       0x80, 0xea, 0xb2, 0x01,
+       0x11, 0x00, 0x00, 0x10,
+       0x02, 0xa6, 0x22, 0x7c,
+       0xff, 0xea, 0xb2, 0x0d,
+       0x11, 0x00, 0x00, 0x10,
+       0xff, 0xea, 0xb2, 0x09,
        0x04, 0x84, 0xf9, 0x30,
        0x00, 0xea, 0x08, 0x81,
        0xff, 0xea, 0xd4, 0x09,
        0x02, 0x84, 0xf9, 0x88,
        0x0d, 0xea, 0x5a, 0x01,
        0x04, 0xa6, 0x4c, 0x05,
-       0x04, 0xa6, 0x64, 0x78,
+       0x04, 0xa6, 0x84, 0x78,
        0xff, 0xea, 0x5a, 0x09,
        0x03, 0x84, 0x59, 0x89,
        0x03, 0xea, 0x4c, 0x01,
-       0x80, 0x1a, 0x64, 0x78,
-       0x08, 0x19, 0x64, 0x78,
+       0x80, 0x1a, 0x84, 0x78,
+       0x08, 0x19, 0x84, 0x78,
        0x08, 0xb0, 0xe0, 0x30,
        0x04, 0xb0, 0xe0, 0x30,
        0x03, 0xb0, 0xf0, 0x30,
@@ -533,259 +561,259 @@ static uint8_t seqprog[] = {
        0x00, 0x86, 0x0d, 0x23,
        0x00, 0x87, 0x0f, 0x23,
        0x01, 0x84, 0xc5, 0x31,
-       0x80, 0x83, 0x25, 0x7c,
+       0x80, 0x83, 0x5d, 0x7c,
        0x02, 0xe2, 0xc4, 0x01,
        0xff, 0xea, 0x4c, 0x09,
        0x01, 0xe2, 0x36, 0x30,
        0xc8, 0x19, 0x32, 0x00,
        0x88, 0x19, 0x32, 0x00,
        0x01, 0xac, 0xd4, 0x99,
-       0x00, 0xe2, 0x64, 0x50,
+       0x00, 0xe2, 0x84, 0x50,
        0xfe, 0xa6, 0x4c, 0x0d,
        0x0b, 0x98, 0xe1, 0x30,
        0xfd, 0xa4, 0x49, 0x09,
-       0x80, 0xa3, 0x39, 0x7c,
+       0x80, 0xa3, 0x71, 0x7c,
        0x02, 0xa4, 0x48, 0x01,
        0x01, 0xa4, 0x36, 0x30,
        0xa8, 0xea, 0x32, 0x00,
        0xfd, 0xa4, 0x49, 0x0b,
        0x05, 0xa3, 0x07, 0x33,
-       0x80, 0x83, 0x45, 0x6c,
+       0x80, 0x83, 0x7d, 0x6c,
        0x02, 0xea, 0x4c, 0x05,
        0xff, 0xea, 0x4c, 0x0d,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x02, 0xa6, 0xe6, 0x6b,
+       0x00, 0xe2, 0x56, 0x59,
+       0x02, 0xa6, 0x10, 0x6c,
        0x80, 0xf9, 0xf2, 0x05,
-       0xc0, 0x33, 0x53, 0x7c,
-       0x03, 0xea, 0x50, 0x59,
+       0xc0, 0x39, 0x8b, 0x7c,
+       0x03, 0xea, 0x64, 0x59,
        0x03, 0xea, 0x04, 0x00,
-       0x20, 0x33, 0x77, 0x7c,
-       0x01, 0x84, 0x5d, 0x6c,
-       0x06, 0xea, 0x50, 0x59,
+       0x20, 0x39, 0xaf, 0x7c,
+       0x01, 0x84, 0x95, 0x6c,
+       0x06, 0xea, 0x64, 0x59,
        0x06, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x7a, 0x44,
-       0x01, 0x00, 0x60, 0x32,
-       0xee, 0x00, 0x66, 0x6c,
+       0x00, 0xe2, 0xb2, 0x44,
+       0x01, 0x00, 0x6c, 0x32,
+       0xee, 0x00, 0x9e, 0x6c,
        0x05, 0xea, 0xb4, 0x00,
-       0x33, 0xea, 0x44, 0x59,
+       0x33, 0xea, 0x5e, 0x59,
        0x33, 0xea, 0x00, 0x00,
        0x80, 0x3d, 0x7a, 0x00,
-       0xfc, 0x42, 0x68, 0x7c,
+       0xfc, 0x42, 0xa0, 0x7c,
        0x7f, 0x3d, 0x7a, 0x08,
-       0x00, 0x30, 0x45, 0x59,
-       0x01, 0x30, 0x01, 0x30,
-       0x09, 0xea, 0x50, 0x59,
+       0x00, 0x36, 0x5f, 0x59,
+       0x01, 0x36, 0x01, 0x30,
+       0x09, 0xea, 0x64, 0x59,
        0x09, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x01, 0xa4, 0x5d, 0x6c,
-       0x00, 0xe2, 0x30, 0x5c,
-       0x20, 0x33, 0x67, 0x02,
-       0x01, 0x00, 0x60, 0x32,
-       0x02, 0xa6, 0x82, 0x7c,
-       0x00, 0xe2, 0x46, 0x5c,
-       0x00, 0xe2, 0x56, 0x58,
-       0x00, 0xe2, 0x66, 0x58,
-       0x00, 0xe2, 0x3a, 0x58,
-       0x00, 0x30, 0x45, 0x59,
-       0x01, 0x30, 0x01, 0x30,
-       0x20, 0x19, 0x82, 0x6c,
-       0x00, 0xe2, 0xb2, 0x5c,
-       0x04, 0x19, 0x9c, 0x6c,
+       0x00, 0xe2, 0x14, 0x42,
+       0x01, 0xa4, 0x95, 0x6c,
+       0x00, 0xe2, 0x68, 0x5c,
+       0x20, 0x39, 0x73, 0x02,
+       0x01, 0x00, 0x6c, 0x32,
+       0x02, 0xa6, 0xba, 0x7c,
+       0x00, 0xe2, 0x7e, 0x5c,
+       0x00, 0xe2, 0x76, 0x58,
+       0x00, 0xe2, 0x86, 0x58,
+       0x00, 0xe2, 0x5a, 0x58,
+       0x00, 0x36, 0x5f, 0x59,
+       0x01, 0x36, 0x01, 0x30,
+       0x20, 0x19, 0xba, 0x6c,
+       0x00, 0xe2, 0xea, 0x5c,
+       0x04, 0x19, 0xd4, 0x6c,
        0x02, 0x19, 0x32, 0x00,
-       0x01, 0x84, 0x9d, 0x7c,
-       0x01, 0x1b, 0x96, 0x7c,
-       0x01, 0x1a, 0x9c, 0x6c,
-       0x00, 0xe2, 0x4c, 0x44,
-       0x80, 0x4b, 0xa2, 0x6c,
-       0x01, 0x4c, 0x9e, 0x7c,
-       0x03, 0x42, 0x4c, 0x6c,
-       0x00, 0xe2, 0xe0, 0x5b,
+       0x01, 0x84, 0xd5, 0x7c,
+       0x01, 0x1b, 0xce, 0x7c,
+       0x01, 0x1a, 0xd4, 0x6c,
+       0x00, 0xe2, 0x84, 0x44,
+       0x80, 0x4b, 0xda, 0x6c,
+       0x01, 0x4c, 0xd6, 0x7c,
+       0x03, 0x42, 0x84, 0x6c,
+       0x00, 0xe2, 0x0a, 0x5c,
        0x80, 0xf9, 0xf2, 0x01,
-       0x04, 0x33, 0xf9, 0x79,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x08, 0x5d, 0xba, 0x6c,
-       0x00, 0xe2, 0x56, 0x58,
-       0x00, 0x30, 0x45, 0x59,
-       0x01, 0x30, 0x01, 0x30,
-       0x02, 0x1b, 0xaa, 0x7c,
-       0x08, 0x5d, 0xb8, 0x7c,
+       0x04, 0x39, 0x15, 0x7a,
+       0x00, 0xe2, 0x14, 0x42,
+       0x08, 0x5d, 0xf2, 0x6c,
+       0x00, 0xe2, 0x76, 0x58,
+       0x00, 0x36, 0x5f, 0x59,
+       0x01, 0x36, 0x01, 0x30,
+       0x02, 0x1b, 0xe2, 0x7c,
+       0x08, 0x5d, 0xf0, 0x7c,
        0x03, 0x68, 0x00, 0x37,
        0x01, 0x84, 0x09, 0x07,
-       0x80, 0x1b, 0xc4, 0x7c,
-       0x80, 0x84, 0xc5, 0x6c,
+       0x80, 0x1b, 0xfc, 0x7c,
+       0x80, 0x84, 0xfd, 0x6c,
        0xff, 0x85, 0x0b, 0x1b,
        0xff, 0x86, 0x0d, 0x23,
        0xff, 0x87, 0x0f, 0x23,
        0xf8, 0x1b, 0x08, 0x0b,
        0xff, 0xea, 0x06, 0x0b,
        0x03, 0x68, 0x00, 0x37,
-       0x00, 0xe2, 0xc4, 0x58,
+       0x00, 0xe2, 0xd6, 0x58,
        0x10, 0xea, 0x18, 0x00,
        0xf9, 0xd9, 0xb2, 0x0d,
        0x01, 0xd9, 0xb2, 0x05,
        0x01, 0x52, 0x48, 0x31,
-       0x20, 0xa4, 0xee, 0x7c,
-       0x20, 0x5b, 0xee, 0x7c,
-       0x80, 0xf9, 0xfc, 0x7c,
+       0x20, 0xa4, 0x26, 0x7d,
+       0x20, 0x5b, 0x26, 0x7d,
+       0x80, 0xf9, 0x34, 0x7d,
        0x02, 0xea, 0xb4, 0x00,
        0x11, 0x00, 0x00, 0x10,
-       0x04, 0x19, 0x08, 0x7d,
+       0x04, 0x19, 0x40, 0x7d,
        0xdf, 0x19, 0x32, 0x08,
-       0x60, 0x5b, 0xe6, 0x6c,
-       0x01, 0x4c, 0xe2, 0x7c,
+       0x60, 0x5b, 0x40, 0x6d,
+       0x01, 0x4c, 0x1a, 0x7d,
        0x20, 0x19, 0x32, 0x00,
        0x01, 0xd9, 0xb2, 0x05,
        0x02, 0xea, 0xb4, 0x00,
        0x01, 0xd9, 0xb2, 0x05,
-       0x10, 0x5b, 0x00, 0x6d,
-       0x08, 0x5b, 0x0a, 0x6d,
-       0x20, 0x5b, 0xfa, 0x6c,
-       0x02, 0x5b, 0x2a, 0x6d,
-       0x0e, 0xea, 0x50, 0x59,
+       0x10, 0x5b, 0x38, 0x6d,
+       0x08, 0x5b, 0x42, 0x6d,
+       0x20, 0x5b, 0x32, 0x6d,
+       0x02, 0x5b, 0x62, 0x6d,
+       0x0e, 0xea, 0x64, 0x59,
        0x0e, 0xea, 0x04, 0x00,
-       0x80, 0xf9, 0xea, 0x6c,
+       0x80, 0xf9, 0x22, 0x6d,
        0xdf, 0x5c, 0xb8, 0x08,
        0x01, 0xd9, 0xb2, 0x05,
-       0x01, 0xa4, 0xe5, 0x6d,
-       0x00, 0xe2, 0x30, 0x5c,
-       0x00, 0xe2, 0x34, 0x5d,
+       0x01, 0xa4, 0x1d, 0x6e,
+       0x00, 0xe2, 0x68, 0x5c,
+       0x00, 0xe2, 0x6c, 0x5d,
        0x01, 0x90, 0x21, 0x1b,
        0x01, 0xd9, 0xb2, 0x05,
-       0x00, 0xe2, 0x32, 0x5b,
+       0x00, 0xe2, 0x52, 0x5b,
        0xf3, 0x96, 0xd5, 0x19,
-       0x00, 0xe2, 0x18, 0x55,
-       0x80, 0x96, 0x19, 0x6d,
-       0x0f, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0x50, 0x55,
+       0x80, 0x96, 0x51, 0x6d,
+       0x0f, 0xea, 0x64, 0x59,
        0x0f, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x20, 0x45,
+       0x00, 0xe2, 0x58, 0x45,
        0x04, 0x8c, 0xe1, 0x30,
        0x01, 0xea, 0xf2, 0x00,
        0x02, 0xea, 0x36, 0x00,
        0xa8, 0xea, 0x32, 0x00,
-       0xff, 0x97, 0x27, 0x7d,
-       0x14, 0xea, 0x50, 0x59,
+       0xff, 0x97, 0x5f, 0x7d,
+       0x14, 0xea, 0x64, 0x59,
        0x14, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x96, 0x5d,
+       0x00, 0xe2, 0xce, 0x5d,
        0x01, 0xd9, 0xb2, 0x05,
        0x09, 0x80, 0xe1, 0x30,
        0x02, 0xea, 0x36, 0x00,
        0xa8, 0xea, 0x32, 0x00,
-       0x00, 0xe2, 0x8e, 0x5d,
+       0x00, 0xe2, 0xc6, 0x5d,
        0x01, 0xd9, 0xb2, 0x05,
-       0x02, 0xa6, 0x44, 0x7d,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x20, 0x5b, 0x52, 0x6d,
-       0xfc, 0x42, 0x3e, 0x7d,
-       0x10, 0x40, 0x40, 0x6d,
-       0x20, 0x4d, 0x42, 0x7d,
-       0x08, 0x5d, 0x52, 0x6d,
-       0x02, 0xa6, 0xe6, 0x6b,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x20, 0x5b, 0x52, 0x6d,
-       0x01, 0x1b, 0x72, 0x6d,
-       0xfc, 0x42, 0x4e, 0x7d,
-       0x10, 0x40, 0x50, 0x6d,
-       0x20, 0x4d, 0x64, 0x78,
-       0x08, 0x5d, 0x64, 0x78,
+       0x02, 0xa6, 0x7c, 0x7d,
+       0x00, 0xe2, 0x56, 0x59,
+       0x20, 0x5b, 0x8a, 0x6d,
+       0xfc, 0x42, 0x76, 0x7d,
+       0x10, 0x40, 0x78, 0x6d,
+       0x20, 0x4d, 0x7a, 0x7d,
+       0x08, 0x5d, 0x8a, 0x6d,
+       0x02, 0xa6, 0x10, 0x6c,
+       0x00, 0xe2, 0x56, 0x59,
+       0x20, 0x5b, 0x8a, 0x6d,
+       0x01, 0x1b, 0xaa, 0x6d,
+       0xfc, 0x42, 0x86, 0x7d,
+       0x10, 0x40, 0x88, 0x6d,
+       0x20, 0x4d, 0x84, 0x78,
+       0x08, 0x5d, 0x84, 0x78,
        0x02, 0x19, 0x32, 0x00,
        0x01, 0x5b, 0x40, 0x31,
-       0x00, 0xe2, 0xb2, 0x5c,
-       0x00, 0xe2, 0x9e, 0x5b,
+       0x00, 0xe2, 0xea, 0x5c,
+       0x00, 0xe2, 0xcc, 0x5b,
        0x20, 0xea, 0xb6, 0x00,
-       0x00, 0xe2, 0xe0, 0x5b,
+       0x00, 0xe2, 0x0a, 0x5c,
        0x20, 0x5c, 0xb8, 0x00,
-       0x04, 0x19, 0x68, 0x6d,
-       0x01, 0x1a, 0x68, 0x6d,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x01, 0x1a, 0x64, 0x78,
+       0x04, 0x19, 0xa0, 0x6d,
+       0x01, 0x1a, 0xa0, 0x6d,
+       0x00, 0xe2, 0x56, 0x59,
+       0x01, 0x1a, 0x84, 0x78,
        0x80, 0xf9, 0xf2, 0x01,
-       0x20, 0xa0, 0xcc, 0x7d,
+       0x20, 0xa0, 0x04, 0x7e,
        0xff, 0x90, 0x21, 0x1b,
-       0x08, 0x92, 0x43, 0x6b,
+       0x08, 0x92, 0x63, 0x6b,
        0x02, 0xea, 0xb4, 0x04,
        0x01, 0xa4, 0x49, 0x03,
-       0x40, 0x5b, 0x82, 0x6d,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x40, 0x5b, 0x82, 0x6d,
-       0x04, 0x5d, 0xe6, 0x7d,
-       0x01, 0x1a, 0xe6, 0x7d,
-       0x20, 0x4d, 0x64, 0x78,
-       0x40, 0x5b, 0xcc, 0x7d,
-       0x04, 0x5d, 0xe6, 0x7d,
-       0x01, 0x1a, 0xe6, 0x7d,
+       0x40, 0x5b, 0xba, 0x6d,
+       0x00, 0xe2, 0x56, 0x59,
+       0x40, 0x5b, 0xba, 0x6d,
+       0x04, 0x5d, 0x1e, 0x7e,
+       0x01, 0x1a, 0x1e, 0x7e,
+       0x20, 0x4d, 0x84, 0x78,
+       0x40, 0x5b, 0x04, 0x7e,
+       0x04, 0x5d, 0x1e, 0x7e,
+       0x01, 0x1a, 0x1e, 0x7e,
        0x80, 0xf9, 0xf2, 0x01,
        0xff, 0x90, 0x21, 0x1b,
-       0x08, 0x92, 0x43, 0x6b,
+       0x08, 0x92, 0x63, 0x6b,
        0x02, 0xea, 0xb4, 0x04,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x01, 0x1b, 0x64, 0x78,
+       0x00, 0xe2, 0x56, 0x59,
+       0x01, 0x1b, 0x84, 0x78,
        0x80, 0xf9, 0xf2, 0x01,
        0x02, 0xea, 0xb4, 0x04,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x01, 0x1b, 0xaa, 0x6d,
-       0x40, 0x5b, 0xb8, 0x7d,
-       0x01, 0x1b, 0xaa, 0x6d,
+       0x00, 0xe2, 0x56, 0x59,
+       0x01, 0x1b, 0xe2, 0x6d,
+       0x40, 0x5b, 0xf0, 0x7d,
+       0x01, 0x1b, 0xe2, 0x6d,
        0x02, 0x19, 0x32, 0x00,
-       0x01, 0x1a, 0x64, 0x78,
+       0x01, 0x1a, 0x84, 0x78,
        0x80, 0xf9, 0xf2, 0x01,
        0xff, 0xea, 0x10, 0x03,
        0x08, 0x92, 0x25, 0x03,
-       0x00, 0xe2, 0x42, 0x43,
-       0x01, 0x1a, 0xb4, 0x7d,
-       0x40, 0x5b, 0xb0, 0x7d,
-       0x01, 0x1a, 0x9e, 0x6d,
-       0xfc, 0x42, 0x64, 0x78,
-       0x01, 0x1a, 0xb8, 0x6d,
-       0x10, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0x62, 0x43,
+       0x01, 0x1a, 0xec, 0x7d,
+       0x40, 0x5b, 0xe8, 0x7d,
+       0x01, 0x1a, 0xd6, 0x6d,
+       0xfc, 0x42, 0x84, 0x78,
+       0x01, 0x1a, 0xf0, 0x6d,
+       0x10, 0xea, 0x64, 0x59,
        0x10, 0xea, 0x04, 0x00,
-       0xfc, 0x42, 0x64, 0x78,
-       0x10, 0x40, 0xbe, 0x6d,
-       0x20, 0x4d, 0x64, 0x78,
-       0x40, 0x5b, 0x9e, 0x6d,
-       0x01, 0x1a, 0x64, 0x78,
+       0xfc, 0x42, 0x84, 0x78,
+       0x10, 0x40, 0xf6, 0x6d,
+       0x20, 0x4d, 0x84, 0x78,
+       0x40, 0x5b, 0xd6, 0x6d,
+       0x01, 0x1a, 0x84, 0x78,
        0x01, 0x90, 0x21, 0x1b,
        0x30, 0x3f, 0xc0, 0x09,
-       0x30, 0xe0, 0x64, 0x60,
-       0x40, 0x4b, 0x64, 0x68,
+       0x30, 0xe0, 0x84, 0x60,
+       0x40, 0x4b, 0x84, 0x68,
        0xff, 0xea, 0x52, 0x01,
-       0xee, 0x00, 0xd2, 0x6d,
+       0xee, 0x00, 0x0c, 0x6e,
        0x80, 0xf9, 0xf2, 0x01,
        0xff, 0x90, 0x21, 0x1b,
        0x02, 0xea, 0xb4, 0x00,
        0x20, 0xea, 0x9a, 0x00,
-       0xf3, 0x42, 0xde, 0x6d,
-       0x12, 0xea, 0x50, 0x59,
+       0xf3, 0x42, 0x16, 0x6e,
+       0x12, 0xea, 0x64, 0x59,
        0x12, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xf8, 0x41,
-       0x0d, 0xea, 0x50, 0x59,
+       0x00, 0xe2, 0x14, 0x42,
+       0x0d, 0xea, 0x64, 0x59,
        0x0d, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0xf8, 0x41,
+       0x00, 0xe2, 0x14, 0x42,
        0x01, 0x90, 0x21, 0x1b,
-       0x11, 0xea, 0x50, 0x59,
+       0x11, 0xea, 0x64, 0x59,
        0x11, 0xea, 0x04, 0x00,
-       0x00, 0xe2, 0x32, 0x5b,
+       0x00, 0xe2, 0x52, 0x5b,
        0x08, 0x5a, 0xb4, 0x00,
-       0x00, 0xe2, 0x0c, 0x5e,
+       0x00, 0xe2, 0x44, 0x5e,
        0xa8, 0xea, 0x32, 0x00,
-       0x00, 0xe2, 0x3e, 0x59,
-       0x80, 0x1a, 0xfa, 0x7d,
-       0x00, 0xe2, 0x0c, 0x5e,
+       0x00, 0xe2, 0x56, 0x59,
+       0x80, 0x1a, 0x32, 0x7e,
+       0x00, 0xe2, 0x44, 0x5e,
        0x80, 0x19, 0x32, 0x00,
-       0x40, 0x5b, 0x00, 0x6e,
-       0x08, 0x5a, 0x00, 0x7e,
-       0x20, 0x4d, 0x64, 0x78,
+       0x40, 0x5b, 0x38, 0x6e,
+       0x08, 0x5a, 0x38, 0x7e,
+       0x20, 0x4d, 0x84, 0x78,
        0x02, 0x84, 0x09, 0x03,
-       0x40, 0x5b, 0xcc, 0x7d,
+       0x40, 0x5b, 0x04, 0x7e,
        0xff, 0x90, 0x21, 0x1b,
        0x80, 0xf9, 0xf2, 0x01,
-       0x08, 0x92, 0x43, 0x6b,
+       0x08, 0x92, 0x63, 0x6b,
        0x02, 0xea, 0xb4, 0x04,
-       0x01, 0x38, 0xe1, 0x30,
-       0x05, 0x39, 0xe3, 0x98,
+       0x01, 0x40, 0xe1, 0x30,
+       0x05, 0x41, 0xe3, 0x98,
        0x01, 0xe0, 0xf4, 0x31,
        0xff, 0xea, 0xc0, 0x09,
-       0x00, 0x3a, 0xe5, 0x20,
-       0x00, 0x3b, 0xe7, 0x20,
+       0x00, 0x42, 0xe5, 0x20,
+       0x00, 0x43, 0xe7, 0x20,
        0x01, 0xfa, 0xc0, 0x31,
        0x04, 0xea, 0xe8, 0x30,
        0xff, 0xea, 0xf0, 0x08,
@@ -794,12 +822,20 @@ static uint8_t seqprog[] = {
 };
 
 typedef int ahd_patch_func_t (struct ahd_softc *ahd);
+static ahd_patch_func_t ahd_patch23_func;
+
+static int
+ahd_patch23_func(struct ahd_softc *ahd)
+{
+       return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+}
+
 static ahd_patch_func_t ahd_patch22_func;
 
 static int
 ahd_patch22_func(struct ahd_softc *ahd)
 {
-       return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+       return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
 }
 
 static ahd_patch_func_t ahd_patch21_func;
@@ -807,7 +843,7 @@ static ahd_patch_func_t ahd_patch21_func;
 static int
 ahd_patch21_func(struct ahd_softc *ahd)
 {
-       return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
+       return ((ahd->flags & AHD_INITIATORROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch20_func;
@@ -815,7 +851,7 @@ static ahd_patch_func_t ahd_patch20_func;
 static int
 ahd_patch20_func(struct ahd_softc *ahd)
 {
-       return ((ahd->features & AHD_RTI) == 0);
+       return ((ahd->flags & AHD_TARGETROLE) != 0);
 }
 
 static ahd_patch_func_t ahd_patch19_func;
@@ -823,7 +859,7 @@ static ahd_patch_func_t ahd_patch19_func;
 static int
 ahd_patch19_func(struct ahd_softc *ahd)
 {
-       return ((ahd->flags & AHD_INITIATORROLE) != 0);
+       return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch18_func;
@@ -831,7 +867,7 @@ static ahd_patch_func_t ahd_patch18_func;
 static int
 ahd_patch18_func(struct ahd_softc *ahd)
 {
-       return ((ahd->flags & AHD_TARGETROLE) != 0);
+       return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
 }
 
 static ahd_patch_func_t ahd_patch17_func;
@@ -839,7 +875,7 @@ static ahd_patch_func_t ahd_patch17_func;
 static int
 ahd_patch17_func(struct ahd_softc *ahd)
 {
-       return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
+       return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch16_func;
@@ -847,7 +883,7 @@ static ahd_patch_func_t ahd_patch16_func;
 static int
 ahd_patch16_func(struct ahd_softc *ahd)
 {
-       return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
+       return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
 }
 
 static ahd_patch_func_t ahd_patch15_func;
@@ -855,7 +891,7 @@ static ahd_patch_func_t ahd_patch15_func;
 static int
 ahd_patch15_func(struct ahd_softc *ahd)
 {
-       return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
+       return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
 }
 
 static ahd_patch_func_t ahd_patch14_func;
@@ -863,7 +899,7 @@ static ahd_patch_func_t ahd_patch14_func;
 static int
 ahd_patch14_func(struct ahd_softc *ahd)
 {
-       return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
+       return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch13_func;
@@ -871,7 +907,7 @@ static ahd_patch_func_t ahd_patch13_func;
 static int
 ahd_patch13_func(struct ahd_softc *ahd)
 {
-       return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
+       return ((ahd->features & AHD_RTI) == 0);
 }
 
 static ahd_patch_func_t ahd_patch12_func;
@@ -879,7 +915,7 @@ static ahd_patch_func_t ahd_patch12_func;
 static int
 ahd_patch12_func(struct ahd_softc *ahd)
 {
-       return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
+       return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch11_func;
@@ -887,7 +923,7 @@ static ahd_patch_func_t ahd_patch11_func;
 static int
 ahd_patch11_func(struct ahd_softc *ahd)
 {
-       return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
+       return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
 }
 
 static ahd_patch_func_t ahd_patch10_func;
@@ -895,7 +931,7 @@ static ahd_patch_func_t ahd_patch10_func;
 static int
 ahd_patch10_func(struct ahd_softc *ahd)
 {
-       return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
+       return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
 }
 
 static ahd_patch_func_t ahd_patch9_func;
@@ -903,7 +939,7 @@ static ahd_patch_func_t ahd_patch9_func;
 static int
 ahd_patch9_func(struct ahd_softc *ahd)
 {
-       return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
+       return ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0);
 }
 
 static ahd_patch_func_t ahd_patch8_func;
@@ -992,147 +1028,149 @@ static struct patch {
        { ahd_patch0_func, 5, 1, 1 },
        { ahd_patch2_func, 6, 1, 2 },
        { ahd_patch0_func, 7, 1, 1 },
-       { ahd_patch3_func, 20, 5, 1 },
-       { ahd_patch2_func, 29, 1, 2 },
-       { ahd_patch0_func, 30, 1, 1 },
-       { ahd_patch1_func, 37, 1, 2 },
-       { ahd_patch0_func, 38, 1, 1 },
-       { ahd_patch2_func, 43, 1, 2 },
-       { ahd_patch0_func, 44, 1, 1 },
-       { ahd_patch2_func, 47, 1, 2 },
-       { ahd_patch0_func, 48, 1, 1 },
-       { ahd_patch2_func, 51, 1, 2 },
-       { ahd_patch0_func, 52, 1, 1 },
-       { ahd_patch2_func, 65, 1, 2 },
-       { ahd_patch0_func, 66, 1, 1 },
-       { ahd_patch2_func, 69, 1, 2 },
-       { ahd_patch0_func, 70, 1, 1 },
-       { ahd_patch1_func, 73, 1, 2 },
-       { ahd_patch0_func, 74, 1, 1 },
-       { ahd_patch4_func, 107, 1, 1 },
-       { ahd_patch2_func, 162, 6, 1 },
-       { ahd_patch1_func, 168, 2, 1 },
-       { ahd_patch5_func, 170, 1, 1 },
-       { ahd_patch2_func, 179, 1, 2 },
-       { ahd_patch0_func, 180, 1, 1 },
-       { ahd_patch6_func, 181, 2, 2 },
-       { ahd_patch0_func, 183, 6, 3 },
-       { ahd_patch2_func, 186, 1, 2 },
-       { ahd_patch0_func, 187, 1, 1 },
-       { ahd_patch2_func, 190, 1, 2 },
-       { ahd_patch0_func, 191, 1, 1 },
-       { ahd_patch7_func, 193, 2, 1 },
-       { ahd_patch5_func, 201, 16, 2 },
-       { ahd_patch0_func, 217, 1, 1 },
-       { ahd_patch8_func, 237, 2, 1 },
-       { ahd_patch1_func, 241, 1, 2 },
-       { ahd_patch0_func, 242, 1, 1 },
-       { ahd_patch7_func, 245, 2, 1 },
-       { ahd_patch1_func, 259, 1, 2 },
-       { ahd_patch0_func, 260, 1, 1 },
-       { ahd_patch1_func, 263, 1, 2 },
-       { ahd_patch0_func, 264, 1, 1 },
-       { ahd_patch2_func, 267, 1, 2 },
-       { ahd_patch0_func, 268, 1, 1 },
-       { ahd_patch1_func, 323, 1, 2 },
-       { ahd_patch0_func, 324, 1, 1 },
-       { ahd_patch2_func, 332, 1, 2 },
-       { ahd_patch0_func, 333, 1, 1 },
-       { ahd_patch2_func, 336, 1, 2 },
-       { ahd_patch0_func, 337, 1, 1 },
-       { ahd_patch1_func, 343, 1, 2 },
-       { ahd_patch0_func, 344, 1, 1 },
-       { ahd_patch1_func, 346, 1, 2 },
-       { ahd_patch0_func, 347, 1, 1 },
-       { ahd_patch9_func, 366, 1, 1 },
-       { ahd_patch9_func, 369, 1, 1 },
-       { ahd_patch9_func, 371, 1, 1 },
-       { ahd_patch9_func, 383, 1, 1 },
-       { ahd_patch1_func, 393, 1, 2 },
-       { ahd_patch0_func, 394, 1, 1 },
-       { ahd_patch1_func, 396, 1, 2 },
-       { ahd_patch0_func, 397, 1, 1 },
-       { ahd_patch1_func, 405, 1, 2 },
-       { ahd_patch0_func, 406, 1, 1 },
-       { ahd_patch2_func, 419, 1, 2 },
-       { ahd_patch0_func, 420, 1, 1 },
-       { ahd_patch10_func, 450, 1, 1 },
-       { ahd_patch1_func, 457, 1, 2 },
-       { ahd_patch0_func, 458, 1, 1 },
-       { ahd_patch2_func, 470, 1, 2 },
-       { ahd_patch0_func, 471, 1, 1 },
-       { ahd_patch11_func, 476, 6, 2 },
-       { ahd_patch0_func, 482, 1, 1 },
-       { ahd_patch12_func, 505, 1, 1 },
-       { ahd_patch13_func, 514, 1, 1 },
-       { ahd_patch14_func, 515, 1, 2 },
-       { ahd_patch0_func, 516, 1, 1 },
-       { ahd_patch15_func, 519, 1, 1 },
-       { ahd_patch14_func, 520, 1, 1 },
-       { ahd_patch16_func, 531, 1, 2 },
-       { ahd_patch0_func, 532, 1, 1 },
-       { ahd_patch1_func, 551, 1, 2 },
-       { ahd_patch0_func, 552, 1, 1 },
-       { ahd_patch1_func, 555, 1, 2 },
-       { ahd_patch0_func, 556, 1, 1 },
-       { ahd_patch2_func, 561, 1, 2 },
-       { ahd_patch0_func, 562, 1, 1 },
-       { ahd_patch2_func, 566, 1, 2 },
-       { ahd_patch0_func, 567, 1, 1 },
-       { ahd_patch1_func, 568, 1, 2 },
-       { ahd_patch0_func, 569, 1, 1 },
-       { ahd_patch2_func, 580, 1, 2 },
-       { ahd_patch0_func, 581, 1, 1 },
-       { ahd_patch17_func, 585, 1, 1 },
-       { ahd_patch18_func, 590, 1, 1 },
-       { ahd_patch19_func, 591, 2, 1 },
-       { ahd_patch18_func, 595, 1, 2 },
-       { ahd_patch0_func, 596, 1, 1 },
-       { ahd_patch2_func, 599, 1, 2 },
-       { ahd_patch0_func, 600, 1, 1 },
-       { ahd_patch2_func, 615, 1, 2 },
-       { ahd_patch0_func, 616, 1, 1 },
-       { ahd_patch20_func, 617, 14, 1 },
-       { ahd_patch1_func, 635, 1, 2 },
-       { ahd_patch0_func, 636, 1, 1 },
-       { ahd_patch20_func, 637, 1, 1 },
-       { ahd_patch1_func, 649, 1, 2 },
-       { ahd_patch0_func, 650, 1, 1 },
-       { ahd_patch1_func, 657, 1, 2 },
-       { ahd_patch0_func, 658, 1, 1 },
-       { ahd_patch17_func, 681, 1, 1 },
-       { ahd_patch17_func, 719, 1, 1 },
-       { ahd_patch1_func, 730, 1, 2 },
-       { ahd_patch0_func, 731, 1, 1 },
-       { ahd_patch1_func, 748, 1, 2 },
-       { ahd_patch0_func, 749, 1, 1 },
-       { ahd_patch1_func, 751, 1, 2 },
-       { ahd_patch0_func, 752, 1, 1 },
-       { ahd_patch1_func, 755, 1, 2 },
-       { ahd_patch0_func, 756, 1, 1 },
-       { ahd_patch21_func, 758, 1, 2 },
-       { ahd_patch0_func, 759, 2, 1 },
-       { ahd_patch22_func, 762, 4, 2 },
-       { ahd_patch0_func, 766, 1, 1 },
-       { ahd_patch22_func, 774, 11, 1 }
+       { ahd_patch3_func, 36, 5, 1 },
+       { ahd_patch2_func, 45, 1, 2 },
+       { ahd_patch0_func, 46, 1, 1 },
+       { ahd_patch1_func, 53, 1, 2 },
+       { ahd_patch0_func, 54, 1, 1 },
+       { ahd_patch2_func, 59, 1, 2 },
+       { ahd_patch0_func, 60, 1, 1 },
+       { ahd_patch2_func, 63, 1, 2 },
+       { ahd_patch0_func, 64, 1, 1 },
+       { ahd_patch2_func, 67, 1, 2 },
+       { ahd_patch0_func, 68, 1, 1 },
+       { ahd_patch4_func, 116, 1, 1 },
+       { ahd_patch2_func, 175, 3, 1 },
+       { ahd_patch1_func, 178, 2, 1 },
+       { ahd_patch5_func, 180, 1, 1 },
+       { ahd_patch2_func, 189, 1, 2 },
+       { ahd_patch0_func, 190, 1, 1 },
+       { ahd_patch6_func, 191, 2, 2 },
+       { ahd_patch0_func, 193, 6, 3 },
+       { ahd_patch2_func, 196, 1, 2 },
+       { ahd_patch0_func, 197, 1, 1 },
+       { ahd_patch2_func, 200, 1, 2 },
+       { ahd_patch0_func, 201, 1, 1 },
+       { ahd_patch3_func, 203, 1, 1 },
+       { ahd_patch7_func, 204, 3, 1 },
+       { ahd_patch3_func, 213, 1, 1 },
+       { ahd_patch5_func, 214, 16, 2 },
+       { ahd_patch0_func, 230, 1, 1 },
+       { ahd_patch8_func, 250, 2, 1 },
+       { ahd_patch1_func, 254, 1, 2 },
+       { ahd_patch0_func, 255, 1, 1 },
+       { ahd_patch7_func, 258, 3, 1 },
+       { ahd_patch1_func, 273, 1, 2 },
+       { ahd_patch0_func, 274, 1, 1 },
+       { ahd_patch1_func, 277, 1, 2 },
+       { ahd_patch0_func, 278, 1, 1 },
+       { ahd_patch2_func, 281, 1, 2 },
+       { ahd_patch0_func, 282, 1, 1 },
+       { ahd_patch9_func, 295, 2, 2 },
+       { ahd_patch0_func, 297, 1, 1 },
+       { ahd_patch1_func, 339, 1, 2 },
+       { ahd_patch0_func, 340, 1, 1 },
+       { ahd_patch2_func, 348, 1, 2 },
+       { ahd_patch0_func, 349, 1, 1 },
+       { ahd_patch2_func, 352, 1, 2 },
+       { ahd_patch0_func, 353, 1, 1 },
+       { ahd_patch1_func, 359, 1, 2 },
+       { ahd_patch0_func, 360, 1, 1 },
+       { ahd_patch1_func, 362, 1, 2 },
+       { ahd_patch0_func, 363, 1, 1 },
+       { ahd_patch10_func, 382, 1, 1 },
+       { ahd_patch10_func, 385, 1, 1 },
+       { ahd_patch10_func, 387, 1, 1 },
+       { ahd_patch10_func, 399, 1, 1 },
+       { ahd_patch1_func, 409, 1, 2 },
+       { ahd_patch0_func, 410, 1, 1 },
+       { ahd_patch1_func, 412, 1, 2 },
+       { ahd_patch0_func, 413, 1, 1 },
+       { ahd_patch1_func, 421, 1, 2 },
+       { ahd_patch0_func, 422, 1, 1 },
+       { ahd_patch2_func, 435, 1, 2 },
+       { ahd_patch0_func, 436, 1, 1 },
+       { ahd_patch11_func, 472, 1, 1 },
+       { ahd_patch1_func, 480, 1, 2 },
+       { ahd_patch0_func, 481, 1, 1 },
+       { ahd_patch2_func, 493, 1, 2 },
+       { ahd_patch0_func, 494, 1, 1 },
+       { ahd_patch12_func, 497, 6, 2 },
+       { ahd_patch0_func, 503, 1, 1 },
+       { ahd_patch13_func, 524, 7, 1 },
+       { ahd_patch14_func, 533, 1, 1 },
+       { ahd_patch15_func, 542, 1, 1 },
+       { ahd_patch16_func, 543, 1, 2 },
+       { ahd_patch0_func, 544, 1, 1 },
+       { ahd_patch17_func, 547, 1, 1 },
+       { ahd_patch16_func, 548, 1, 1 },
+       { ahd_patch18_func, 559, 1, 2 },
+       { ahd_patch0_func, 560, 1, 1 },
+       { ahd_patch1_func, 579, 1, 2 },
+       { ahd_patch0_func, 580, 1, 1 },
+       { ahd_patch1_func, 583, 1, 2 },
+       { ahd_patch0_func, 584, 1, 1 },
+       { ahd_patch2_func, 589, 1, 2 },
+       { ahd_patch0_func, 590, 1, 1 },
+       { ahd_patch2_func, 594, 1, 2 },
+       { ahd_patch0_func, 595, 1, 1 },
+       { ahd_patch1_func, 596, 1, 2 },
+       { ahd_patch0_func, 597, 1, 1 },
+       { ahd_patch2_func, 608, 1, 2 },
+       { ahd_patch0_func, 609, 1, 1 },
+       { ahd_patch19_func, 613, 1, 1 },
+       { ahd_patch20_func, 618, 1, 1 },
+       { ahd_patch21_func, 619, 2, 1 },
+       { ahd_patch20_func, 623, 1, 2 },
+       { ahd_patch0_func, 624, 1, 1 },
+       { ahd_patch2_func, 627, 1, 2 },
+       { ahd_patch0_func, 628, 1, 1 },
+       { ahd_patch2_func, 643, 1, 2 },
+       { ahd_patch0_func, 644, 1, 1 },
+       { ahd_patch13_func, 645, 14, 1 },
+       { ahd_patch1_func, 663, 1, 2 },
+       { ahd_patch0_func, 664, 1, 1 },
+       { ahd_patch13_func, 665, 1, 1 },
+       { ahd_patch1_func, 677, 1, 2 },
+       { ahd_patch0_func, 678, 1, 1 },
+       { ahd_patch1_func, 685, 1, 2 },
+       { ahd_patch0_func, 686, 1, 1 },
+       { ahd_patch19_func, 709, 1, 1 },
+       { ahd_patch19_func, 747, 1, 1 },
+       { ahd_patch1_func, 758, 1, 2 },
+       { ahd_patch0_func, 759, 1, 1 },
+       { ahd_patch1_func, 776, 1, 2 },
+       { ahd_patch0_func, 777, 1, 1 },
+       { ahd_patch1_func, 779, 1, 2 },
+       { ahd_patch0_func, 780, 1, 1 },
+       { ahd_patch1_func, 783, 1, 2 },
+       { ahd_patch0_func, 784, 1, 1 },
+       { ahd_patch22_func, 786, 1, 2 },
+       { ahd_patch0_func, 787, 2, 1 },
+       { ahd_patch23_func, 790, 4, 2 },
+       { ahd_patch0_func, 794, 1, 1 },
+       { ahd_patch23_func, 802, 11, 1 }
 };
 
 static struct cs {
        uint16_t        begin;
        uint16_t        end;
 } critical_sections[] = {
-       { 11, 12 },
-       { 13, 14 },
-       { 29, 42 },
-       { 56, 59 },
-       { 101, 128 },
-       { 129, 157 },
-       { 159, 162 },
-       { 170, 178 },
-       { 201, 250 },
-       { 681, 697 },
-       { 697, 711 },
-       { 721, 725 }
+       { 17, 28 },
+       { 29, 30 },
+       { 47, 58 },
+       { 61, 63 },
+       { 65, 66 },
+       { 72, 92 },
+       { 110, 137 },
+       { 138, 175 },
+       { 180, 188 },
+       { 213, 264 },
+       { 425, 433 },
+       { 443, 445 },
+       { 448, 457 },
+       { 709, 739 },
+       { 749, 753 }
 };
 
 static const int num_critical_sections = sizeof(critical_sections)
index fd389e9f9460a7af31fd9510848f5dd13fac3b96..051970efba6803a0486e6b6a8b09573d71201b07 100644 (file)
@@ -375,7 +375,7 @@ static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
                                         struct scsi_cmnd *cmd);
 static void ahc_linux_sem_timeout(u_long arg);
 static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
-static void ahc_linux_release_simq(u_long arg);
+static void ahc_linux_release_simq(struct ahc_softc *ahc);
 static int  ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
 static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
 static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc,
@@ -1073,7 +1073,6 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa
                return (ENOMEM);
 
        *((struct ahc_softc **)host->hostdata) = ahc;
-       ahc_lock(ahc, &s);
        ahc->platform_data->host = host;
        host->can_queue = AHC_MAX_QUEUE;
        host->cmd_per_lun = 2;
@@ -1084,7 +1083,9 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa
        host->max_lun = AHC_NUM_LUNS;
        host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
        host->sg_tablesize = AHC_NSEG;
+       ahc_lock(ahc, &s);
        ahc_set_unit(ahc, ahc_linux_unit++);
+       ahc_unlock(ahc, &s);
        sprintf(buf, "scsi%d", host->host_no);
        new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
        if (new_name != NULL) {
@@ -1094,7 +1095,6 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa
        host->unique_id = ahc->unit;
        ahc_linux_initialize_scsi_bus(ahc);
        ahc_intr_enable(ahc, TRUE);
-       ahc_unlock(ahc, &s);
 
        host->transportt = ahc_linux_transport_template;
 
@@ -1120,10 +1120,13 @@ ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc)
 {
        int i;
        int numtarg;
+       unsigned long s;
 
        i = 0;
        numtarg = 0;
 
+       ahc_lock(ahc, &s);
+
        if (aic7xxx_no_reset != 0)
                ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B);
 
@@ -1170,16 +1173,12 @@ ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc)
                ahc_update_neg_request(ahc, &devinfo, tstate,
                                       tinfo, AHC_NEG_ALWAYS);
        }
+       ahc_unlock(ahc, &s);
        /* Give the bus some time to recover */
        if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {
                ahc_linux_freeze_simq(ahc);
-               init_timer(&ahc->platform_data->reset_timer);
-               ahc->platform_data->reset_timer.data = (u_long)ahc;
-               ahc->platform_data->reset_timer.expires =
-                   jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;
-               ahc->platform_data->reset_timer.function =
-                   ahc_linux_release_simq;
-               add_timer(&ahc->platform_data->reset_timer);
+               msleep(AIC7XXX_RESET_DELAY);
+               ahc_linux_release_simq(ahc);
        }
 }
 
@@ -2059,6 +2058,9 @@ ahc_linux_sem_timeout(u_long arg)
 static void
 ahc_linux_freeze_simq(struct ahc_softc *ahc)
 {
+       unsigned long s;
+
+       ahc_lock(ahc, &s);
        ahc->platform_data->qfrozen++;
        if (ahc->platform_data->qfrozen == 1) {
                scsi_block_requests(ahc->platform_data->host);
@@ -2068,17 +2070,15 @@ ahc_linux_freeze_simq(struct ahc_softc *ahc)
                                        CAM_LUN_WILDCARD, SCB_LIST_NULL,
                                        ROLE_INITIATOR, CAM_REQUEUE_REQ);
        }
+       ahc_unlock(ahc, &s);
 }
 
 static void
-ahc_linux_release_simq(u_long arg)
+ahc_linux_release_simq(struct ahc_softc *ahc)
 {
-       struct ahc_softc *ahc;
        u_long s;
        int    unblock_reqs;
 
-       ahc = (struct ahc_softc *)arg;
-
        unblock_reqs = 0;
        ahc_lock(ahc, &s);
        if (ahc->platform_data->qfrozen > 0)
index f2a95447142c38db38a2e41ef023975dccc43420..e0edacae895f425ffda730dbe8b1a4efb2049a71 100644 (file)
@@ -223,9 +223,6 @@ int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t);
  */
 #define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op)
 
-/************************** Timer DataStructures ******************************/
-typedef struct timer_list ahc_timer_t;
-
 /********************************** Includes **********************************/
 #ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT
 #define AIC_DEBUG_REGISTERS 1
@@ -235,30 +232,9 @@ typedef struct timer_list ahc_timer_t;
 #include "aic7xxx.h"
 
 /***************************** Timer Facilities *******************************/
-#define ahc_timer_init init_timer
-#define ahc_timer_stop del_timer_sync
-typedef void ahc_linux_callback_t (u_long);  
-static __inline void ahc_timer_reset(ahc_timer_t *timer, int usec,
-                                    ahc_callback_t *func, void *arg);
-static __inline void ahc_scb_timer_reset(struct scb *scb, u_int usec);
-
-static __inline void
-ahc_timer_reset(ahc_timer_t *timer, int usec, ahc_callback_t *func, void *arg)
-{
-       struct ahc_softc *ahc;
-
-       ahc = (struct ahc_softc *)arg;
-       del_timer(timer);
-       timer->data = (u_long)arg;
-       timer->expires = jiffies + (usec * HZ)/1000000;
-       timer->function = (ahc_linux_callback_t*)func;
-       add_timer(timer);
-}
-
 static __inline void
 ahc_scb_timer_reset(struct scb *scb, u_int usec)
 {
-       mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000);
 }
 
 /***************************** SMP support ************************************/
@@ -393,7 +369,6 @@ struct ahc_platform_data {
 
        spinlock_t               spin_lock;
        u_int                    qfrozen;
-       struct timer_list        reset_timer;
        struct semaphore         eh_sem;
        struct Scsi_Host        *host;          /* pointer to scsi host */
 #define AHC_LINUX_NOIRQ        ((uint32_t)~0)
index b3b2e2237eb39dc9d930b6633ea7b9d5790c4bfb..5f586140e05717a575f2f1a8103dd0edfe635486 100644 (file)
@@ -39,9 +39,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#69 $
- *
- * $FreeBSD$
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#79 $
  */
 
 #ifdef __linux__
@@ -393,6 +391,12 @@ struct ahc_pci_identity ahc_pci_ident_table [] =
                "Adaptec aic7892 Ultra160 SCSI adapter (ARO)",
                ahc_aic7892_setup
        },
+       {
+               ID_AHA_2915_30LP,
+               ID_ALL_MASK,
+               "Adaptec 2915/30LP Ultra160 SCSI adapter",
+               ahc_aic7892_setup
+       },
        /* aic7895 based controllers */ 
        {
                ID_AHA_2940U_DUAL,
@@ -1193,9 +1197,19 @@ ahc_pci_test_register_access(struct ahc_softc *ahc)
         * use for this test.
         */
        hcntrl = ahc_inb(ahc, HCNTRL);
+
        if (hcntrl == 0xFF)
                goto fail;
 
+       if ((hcntrl & CHIPRST) != 0) {
+               /*
+                * The chip has not been initialized since
+                * PCI/EISA/VLB bus reset.  Don't trust
+                * "left over BIOS data".
+                */
+               ahc->flags |= AHC_NO_BIOS_INIT;
+       }
+
        /*
         * Next create a situation where write combining
         * or read prefetching could be initiated by the
@@ -1307,6 +1321,10 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
                        sd.sd_chip = C56_66;
                }
                ahc_release_seeprom(&sd);
+
+               /* Remember the SEEPROM type for later */
+               if (sd.sd_chip == C56_66)
+                       ahc->flags |= AHC_LARGE_SEEPROM;
        }
 
        if (!have_seeprom) {
index be27fcb2034693e978830e6a0b8b1e6a5561f1e1..263f85da405ec826991abf586c8a70ab065603ae 100644 (file)
 #define ID_AHA_29160C                  0x0080900562209005ull
 #define ID_AHA_29160B                  0x00809005E2209005ull
 #define ID_AHA_19160B                  0x0081900562A19005ull
+#define ID_AHA_2915_30LP               0x0082900502109005ull
 
 #define ID_AIC7896                     0x005F9005FFFF9005ull
 #define ID_AIC7896_ARO                 0x00539005FFFF9005ull
index 33d56c34494489c773125dd53ee346a4d55dd69a..770f1647e4d6796fde8f6b81cf1c2bc6fe80a1a7 100644 (file)
@@ -1290,7 +1290,7 @@ static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer);
  *
  ***************************************************************************/
 
-static inline unsigned char
+static unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
 #ifdef MMAPIO
@@ -1309,7 +1309,7 @@ aic_inb(struct aic7xxx_host *p, long port)
 #endif
 }
 
-static inline void
+static void
 aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
 {
 #ifdef MMAPIO
index 4299fabca5547469dc9fe59aee9f04c4c48fd529..c3f27285db1bd91bf5d7d0955c35797e7dc16ff2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/completion.h>
 #include <linux/compat.h>
 #include <linux/chio.h>                        /* here are all the ioctls */
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -111,7 +112,7 @@ typedef struct {
        u_int               counts[CH_TYPES];
        u_int               unit_attention;
        u_int               voltags;
-       struct semaphore    lock;
+       struct mutex        lock;
 } scsi_changer;
 
 static LIST_HEAD(ch_devlist);
@@ -565,7 +566,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
        u_char data[16];
        unsigned int i;
        
-       down(&ch->lock);
+       mutex_lock(&ch->lock);
        for (i = 0; i < ch->counts[type]; i++) {
                if (0 != ch_read_element_status
                    (ch, ch->firsts[type]+i,data)) {
@@ -582,7 +583,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
                if (0 != retval)
                        break;
        }
-       up(&ch->lock);
+       mutex_unlock(&ch->lock);
        return retval;
 }
 
@@ -687,11 +688,11 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        dprintk("CHIOPOSITION: invalid parameter\n");
                        return -EBADSLT;
                }
-               down(&ch->lock);
+               mutex_lock(&ch->lock);
                retval = ch_position(ch,0,
                                     ch->firsts[pos.cp_type] + pos.cp_unit,
                                     pos.cp_flags & CP_INVERT);
-               up(&ch->lock);
+               mutex_unlock(&ch->lock);
                return retval;
        }
        
@@ -708,12 +709,12 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        return -EBADSLT;
                }
                
-               down(&ch->lock);
+               mutex_lock(&ch->lock);
                retval = ch_move(ch,0,
                                 ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
                                 ch->firsts[mv.cm_totype]   + mv.cm_tounit,
                                 mv.cm_flags & CM_INVERT);
-               up(&ch->lock);
+               mutex_unlock(&ch->lock);
                return retval;
        }
 
@@ -731,14 +732,14 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        return -EBADSLT;
                }
                
-               down(&ch->lock);
+               mutex_lock(&ch->lock);
                retval = ch_exchange
                        (ch,0,
                         ch->firsts[mv.ce_srctype]  + mv.ce_srcunit,
                         ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
                         ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
                         mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
-               up(&ch->lock);
+               mutex_unlock(&ch->lock);
                return retval;
        }
 
@@ -772,7 +773,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
                if (!buffer)
                        return -ENOMEM;
-               down(&ch->lock);
+               mutex_lock(&ch->lock);
                
        voltag_retry:
                memset(cmd,0,sizeof(cmd));
@@ -823,7 +824,7 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        goto voltag_retry;
                }
                kfree(buffer);
-               up(&ch->lock);
+               mutex_unlock(&ch->lock);
                
                if (copy_to_user(argp, &cge, sizeof (cge)))
                        return -EFAULT;
@@ -832,9 +833,9 @@ static int ch_ioctl(struct inode * inode, struct file * file,
 
        case CHIOINITELEM:
        {
-               down(&ch->lock);
+               mutex_lock(&ch->lock);
                retval = ch_init_elem(ch);
-               up(&ch->lock);
+               mutex_unlock(&ch->lock);
                return retval;
        }
                
@@ -851,12 +852,12 @@ static int ch_ioctl(struct inode * inode, struct file * file,
                        return -EBADSLT;
                }
                elem = ch->firsts[csv.csv_type] + csv.csv_unit;
-               down(&ch->lock);
+               mutex_lock(&ch->lock);
                retval = ch_set_voltag(ch, elem,
                                       csv.csv_flags & CSV_AVOLTAG,
                                       csv.csv_flags & CSV_CLEARTAG,
                                       csv.csv_voltag);
-               up(&ch->lock);
+               mutex_unlock(&ch->lock);
                return retval;
        }
 
@@ -929,7 +930,7 @@ static int ch_probe(struct device *dev)
        memset(ch,0,sizeof(*ch));
        ch->minor = ch_devcount;
        sprintf(ch->name,"ch%d",ch->minor);
-       init_MUTEX(&ch->lock);
+       mutex_init(&ch->lock);
        ch->device = sd;
        ch_readconfig(ch);
        if (init)
index 6252b9ddc01e3eec6fd72268d6fc764b1d3a8bb7..6e6b293dcb28b67dc5922089ff586dc2e0eeaeaa 100644 (file)
@@ -61,6 +61,7 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+#include <linux/mutex.h>
 
 #include <asm/processor.h>     /* for boot_cpu_data */
 #include <asm/pgtable.h>
@@ -106,7 +107,7 @@ static dpt_sig_S DPTI_sig = {
  *============================================================================
  */
 
-static DECLARE_MUTEX(adpt_configuration_lock);
+static DEFINE_MUTEX(adpt_configuration_lock);
 
 static struct i2o_sys_tbl *sys_tbl = NULL;
 static int sys_tbl_ind = 0;
@@ -537,13 +538,13 @@ static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, of
         */
 
        // Find HBA (host bus adapter) we are looking for
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
        for (pHba = hba_chain; pHba; pHba = pHba->next) {
                if (pHba->host == host) {
                        break;  /* found adapter */
                }
        }
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
        if (pHba == NULL) {
                return 0;
        }
@@ -898,6 +899,12 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
        if(pci_enable_device(pDev)) {
                return -EINVAL;
        }
+
+       if (pci_request_regions(pDev, "dpt_i2o")) {
+               PERROR("dpti: adpt_config_hba: pci request region failed\n");
+               return -EINVAL;
+       }
+
        pci_set_master(pDev);
        if (pci_set_dma_mask(pDev, 0xffffffffffffffffULL) &&
            pci_set_dma_mask(pDev, 0xffffffffULL))
@@ -923,10 +930,6 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
                raptorFlag = TRUE;
        }
 
-       if (pci_request_regions(pDev, "dpt_i2o")) {
-               PERROR("dpti: adpt_config_hba: pci request region failed\n");
-               return -EINVAL;
-       }
        base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
        if (!base_addr_virt) {
                pci_release_regions(pDev);
@@ -958,7 +961,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
        }
        memset(pHba, 0, sizeof(adpt_hba));
 
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
 
        if(hba_chain != NULL){
                for(p = hba_chain; p->next; p = p->next);
@@ -971,7 +974,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
        sprintf(pHba->name, "dpti%d", hba_count);
        hba_count++;
        
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
 
        pHba->pDev = pDev;
        pHba->base_addr_phys = base_addr0_phys;
@@ -1027,7 +1030,7 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
        struct adpt_device* pNext;
 
 
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
        // scsi_unregister calls our adpt_release which
        // does a quiese
        if(pHba->host){
@@ -1046,7 +1049,7 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
        }
 
        hba_count--;
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
 
        iounmap(pHba->base_addr_virt);
        pci_release_regions(pHba->pDev);
@@ -1549,7 +1552,7 @@ static int adpt_i2o_parse_lct(adpt_hba* pHba)
  
 static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d)
 {
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
        d->controller=pHba;
        d->owner=NULL;
        d->next=pHba->devices;
@@ -1560,7 +1563,7 @@ static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d)
        pHba->devices=d;
        *d->dev_name = 0;
 
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
        return 0;
 }
 
@@ -1575,24 +1578,24 @@ static int adpt_open(struct inode *inode, struct file *file)
        if (minor >= hba_count) {
                return -ENXIO;
        }
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
        for (pHba = hba_chain; pHba; pHba = pHba->next) {
                if (pHba->unit == minor) {
                        break;  /* found adapter */
                }
        }
        if (pHba == NULL) {
-               up(&adpt_configuration_lock);
+               mutex_unlock(&adpt_configuration_lock);
                return -ENXIO;
        }
 
 //     if(pHba->in_use){
-       //      up(&adpt_configuration_lock);
+       //      mutex_unlock(&adpt_configuration_lock);
 //             return -EBUSY;
 //     }
 
        pHba->in_use = 1;
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
 
        return 0;
 }
@@ -1606,13 +1609,13 @@ static int adpt_close(struct inode *inode, struct file *file)
        if (minor >= hba_count) {
                return -ENXIO;
        }
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
        for (pHba = hba_chain; pHba; pHba = pHba->next) {
                if (pHba->unit == minor) {
                        break;  /* found adapter */
                }
        }
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
        if (pHba == NULL) {
                return -ENXIO;
        }
@@ -1910,13 +1913,13 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
        if (minor >= DPTI_MAX_HBA){
                return -ENXIO;
        }
-       down(&adpt_configuration_lock);
+       mutex_lock(&adpt_configuration_lock);
        for (pHba = hba_chain; pHba; pHba = pHba->next) {
                if (pHba->unit == minor) {
                        break;  /* found adapter */
                }
        }
-       up(&adpt_configuration_lock);
+       mutex_unlock(&adpt_configuration_lock);
        if(pHba == NULL){
                return -ENXIO;
        }
index 66783c860a198f502bba35147cfbbbd7ee87aa16..588107923499772229fdab7df9cc20bf27f86606 100644 (file)
@@ -156,16 +156,16 @@ EXPORT_SYMBOL(scsi_host_set_state);
 void scsi_remove_host(struct Scsi_Host *shost)
 {
        unsigned long flags;
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        spin_lock_irqsave(shost->host_lock, flags);
        if (scsi_host_set_state(shost, SHOST_CANCEL))
                if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
                        spin_unlock_irqrestore(shost->host_lock, flags);
-                       up(&shost->scan_mutex);
+                       mutex_unlock(&shost->scan_mutex);
                        return;
                }
        spin_unlock_irqrestore(shost->host_lock, flags);
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
        scsi_forget_host(shost);
        scsi_proc_host_rm(shost);
 
@@ -320,7 +320,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        INIT_LIST_HEAD(&shost->starved_list);
        init_waitqueue_head(&shost->host_wait);
 
-       init_MUTEX(&shost->scan_mutex);
+       mutex_init(&shost->scan_mutex);
 
        shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */
        shost->dma_channel = 0xff;
index 3882d48a42bf5c5e9fa739b529059bcb3211e007..e5e1ca44e1eea831e17814c84d81db91b62be2cf 100644 (file)
@@ -1319,6 +1319,9 @@ ips_slave_configure(struct scsi_device * SDptr)
                        min = ha->max_cmds - 1;
                scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
        }
+
+       SDptr->skip_ms_page_8 = 1;
+       SDptr->skip_ms_page_3f = 1;
        return 0;
 }
 #endif
index 10bcf42cb65c0a0eaf021b4052a068019c9658d2..780bfcc67096cff51069cf94bc1e4ae6374ceafe 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/kfifo.h>
 #include <linux/scatterlist.h>
+#include <linux/mutex.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -86,35 +87,32 @@ iscsi_buf_init_virt(struct iscsi_buf *ibuf, char *vbuf, int size)
 {
        sg_init_one(&ibuf->sg, (u8 *)vbuf, size);
        ibuf->sent = 0;
+       ibuf->use_sendmsg = 0;
 }
 
 static inline void
 iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
 {
-       ibuf->sg.page = (void*)vbuf;
-       ibuf->sg.offset = (unsigned int)-1;
+       ibuf->sg.page = virt_to_page(vbuf);
+       ibuf->sg.offset = offset_in_page(vbuf);
        ibuf->sg.length = size;
        ibuf->sent = 0;
-}
-
-static inline void*
-iscsi_buf_iov_base(struct iscsi_buf *ibuf)
-{
-       return (char*)ibuf->sg.page + ibuf->sent;
+       ibuf->use_sendmsg = 1;
 }
 
 static inline void
 iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
 {
+       ibuf->sg.page = sg->page;
+       ibuf->sg.offset = sg->offset;
+       ibuf->sg.length = sg->length;
        /*
         * Fastpath: sg element fits into single page
         */
-       if (sg->length + sg->offset <= PAGE_SIZE && page_count(sg->page) >= 2) {
-               ibuf->sg.page = sg->page;
-               ibuf->sg.offset = sg->offset;
-               ibuf->sg.length = sg->length;
-       } else
-               iscsi_buf_init_iov(ibuf, page_address(sg->page), sg->length);
+       if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page))
+               ibuf->use_sendmsg = 0;
+       else
+               ibuf->use_sendmsg = 1;
        ibuf->sent = 0;
 }
 
@@ -356,7 +354,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                struct scsi_cmnd *sc = ctask->sc;
 
                conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
-               if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
+               if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
                        int res_count = be32_to_cpu(rhdr->residual_count);
 
                        if (res_count > 0 &&
@@ -366,9 +364,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                        } else
                                sc->result = (DID_BAD_TARGET << 16) |
                                        rhdr->cmd_status;
-               } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
-                       sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
-               else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) {
+               } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
                        sc->resid = be32_to_cpu(rhdr->residual_count);
                        sc->result = (DID_OK << 16) | rhdr->cmd_status;
                } else
@@ -529,7 +525,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        __kfifo_put(ctask->r2tqueue, (void*)&r2t, sizeof(void*));
        __kfifo_put(conn->writequeue, (void*)&ctask, sizeof(void*));
 
-       schedule_work(&conn->xmitwork);
+       scsi_queue_work(session->host, &conn->xmitwork);
        conn->r2t_pdus_cnt++;
        spin_unlock(&session->lock);
 
@@ -686,7 +682,7 @@ iscsi_hdr_recv(struct iscsi_conn *conn)
                switch(conn->in.opcode) {
                case ISCSI_OP_LOGIN_RSP:
                case ISCSI_OP_TEXT_RSP:
-               case ISCSI_OP_LOGOUT_RSP: 
+               case ISCSI_OP_LOGOUT_RSP:
                        rc = iscsi_check_assign_cmdsn(session,
                                                 (struct iscsi_nopin*)hdr);
                        if (rc)
@@ -727,12 +723,12 @@ iscsi_hdr_recv(struct iscsi_conn *conn)
                        }
                        spin_unlock(&session->lock);
                        break;
-               case ISCSI_OP_NOOP_IN: 
+               case ISCSI_OP_NOOP_IN:
                        if (hdr->ttt != ISCSI_RESERVED_TAG) {
                                rc = ISCSI_ERR_PROTO;
                                break;
                        }
-                       rc = iscsi_check_assign_cmdsn(session, 
+                       rc = iscsi_check_assign_cmdsn(session,
                                                (struct iscsi_nopin*)hdr);
                        if (rc)
                                break;
@@ -767,7 +763,7 @@ iscsi_hdr_recv(struct iscsi_conn *conn)
                                if (!rc && hdr->ttt != ISCSI_RESERVED_TAG)
                                        rc = iscsi_recv_pdu(iscsi_handle(conn),
                                                            hdr, NULL, 0);
-                       } else 
+                       } else
                                rc = ISCSI_ERR_PROTO;
                        break;
                case ISCSI_OP_REJECT:
@@ -929,7 +925,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
                                      sc->request_bufflen, ctask->data_offset);
                if (rc == -EAGAIN)
                        return rc;
-               if (conn->datadgst_en) 
+               if (conn->datadgst_en)
                        iscsi_recv_digest_update(conn, sc->request_buffer, i);
                rc = 0;
                goto done;
@@ -1024,7 +1020,7 @@ iscsi_data_recv(struct iscsi_conn *conn)
                conn->in.hdr = &conn->hdr;
                conn->senselen = (conn->data[0] << 8) | conn->data[1];
                rc = iscsi_cmd_rsp(conn, conn->in.ctask);
-               if (!rc && conn->datadgst_en) 
+               if (!rc && conn->datadgst_en)
                        iscsi_recv_digest_update(conn, conn->data,
                                                 conn->in.datalen);
        }
@@ -1051,7 +1047,7 @@ iscsi_data_recv(struct iscsi_conn *conn)
                rc = iscsi_recv_pdu(iscsi_handle(conn), conn->in.hdr,
                                    conn->data, conn->in.datalen);
 
-               if (!rc && conn->datadgst_en && 
+               if (!rc && conn->datadgst_en &&
                        conn->in.opcode != ISCSI_OP_LOGIN_RSP)
                        iscsi_recv_digest_update(conn, conn->data,
                                                conn->in.datalen);
@@ -1271,7 +1267,7 @@ iscsi_write_space(struct sock *sk)
        conn->old_write_space(sk);
        debug_tcp("iscsi_write_space: cid %d\n", conn->id);
        clear_bit(SUSPEND_BIT, &conn->suspend_tx);
-       schedule_work(&conn->xmitwork);
+       scsi_queue_work(conn->session->host, &conn->xmitwork);
 }
 
 static void
@@ -1312,35 +1308,25 @@ iscsi_conn_restore_callbacks(struct iscsi_conn *conn)
  * @buf: buffer to write from
  * @size: actual size to write
  * @flags: socket's flags
- *
- * Notes:
- *     depending on buffer will use tcp_sendpage() or tcp_sendmsg().
- *     buf->sg.offset == -1 tells us that buffer is non S/G and forces
- *     to use tcp_sendmsg().
  */
 static inline int
-iscsi_send(struct socket *sk, struct iscsi_buf *buf, int size, int flags)
+iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
 {
-       int res;
-
-       if ((int)buf->sg.offset >= 0) {
-               int offset = buf->sg.offset + buf->sent;
-
-               /* tcp_sendpage */
-               res = sk->ops->sendpage(sk, buf->sg.page, offset, size, flags);
-       } else {
-               struct msghdr msg;
-
-               buf->iov.iov_base = iscsi_buf_iov_base(buf);
-               buf->iov.iov_len = size;
-
-               memset(&msg, 0, sizeof(struct msghdr));
-
-               /* tcp_sendmsg */
-               res = kernel_sendmsg(sk, &msg, &buf->iov, 1, size);
-       }
+       struct socket *sk = conn->sock;
+       int offset = buf->sg.offset + buf->sent;
 
-       return res;
+       /*
+        * if we got use_sg=0 or are sending something we kmallocd
+        * then we did not have to do kmap (kmap returns page_address)
+        *
+        * if we got use_sg > 0, but had to drop down, we do not
+        * set clustering so this should only happen for that
+        * slab case.
+        */
+       if (buf->use_sendmsg)
+               return sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
+       else
+               return conn->sendpage(sk, buf->sg.page, offset, size, flags);
 }
 
 /**
@@ -1355,7 +1341,6 @@ iscsi_send(struct socket *sk, struct iscsi_buf *buf, int size, int flags)
 static inline int
 iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
 {
-       struct socket *sk = conn->sock;
        int flags = 0; /* MSG_DONTWAIT; */
        int res, size;
 
@@ -1364,7 +1349,7 @@ iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen)
        if (buf->sent + size != buf->sg.length || datalen)
                flags |= MSG_MORE;
 
-       res = iscsi_send(sk, buf, size, flags);
+       res = iscsi_send(conn, buf, size, flags);
        debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res);
        if (res >= 0) {
                conn->txdata_octets += res;
@@ -1395,7 +1380,6 @@ static inline int
 iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
               int *count, int *sent)
 {
-       struct socket *sk = conn->sock;
        int flags = 0; /* MSG_DONTWAIT; */
        int res, size;
 
@@ -1406,7 +1390,7 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
        if (buf->sent + size != buf->sg.length || *count != size)
                flags |= MSG_MORE;
 
-       res = iscsi_send(sk, buf, size, flags);
+       res = iscsi_send(conn, buf, size, flags);
        debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n",
                  size, buf->sent, *count, *sent, res);
        if (res >= 0) {
@@ -1434,20 +1418,7 @@ iscsi_data_digest_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        ctask->digest_count = 4;
 }
 
-static inline void
-iscsi_buf_data_digest_update(struct iscsi_conn *conn, struct iscsi_buf *buf)
-{
-       struct scatterlist sg;
-
-       if (buf->sg.offset != -1)
-               crypto_digest_update(conn->data_tx_tfm, &buf->sg, 1);
-       else {
-               sg_init_one(&sg, (char *)buf->sg.page, buf->sg.length);
-               crypto_digest_update(conn->data_tx_tfm, &sg, 1);
-       }
-}
-
-static inline int
+static int
 iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                        struct iscsi_buf *buf, uint32_t *digest, int final)
 {
@@ -1680,7 +1651,7 @@ iscsi_cmd_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
                zero_data(ctask->hdr.dlength);
        }
 
-       iscsi_buf_init_virt(&ctask->headbuf, (char*)&ctask->hdr, 
+       iscsi_buf_init_virt(&ctask->headbuf, (char*)&ctask->hdr,
                            sizeof(struct iscsi_hdr));
        conn->scsicmd_pdus_cnt++;
 }
@@ -1746,7 +1717,7 @@ static inline int
 handle_xmstate_r_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
        ctask->xmstate &= ~XMSTATE_R_HDR;
-       if (conn->hdrdgst_en) 
+       if (conn->hdrdgst_en)
                iscsi_hdr_digest(conn, &ctask->headbuf, (u8*)ctask->hdrext);
        if (!iscsi_sendhdr(conn, &ctask->headbuf, 0)) {
                BUG_ON(ctask->xmstate != XMSTATE_IDLE);
@@ -1760,7 +1731,7 @@ static inline int
 handle_xmstate_w_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
 {
        ctask->xmstate &= ~XMSTATE_W_HDR;
-       if (conn->hdrdgst_en) 
+       if (conn->hdrdgst_en)
                iscsi_hdr_digest(conn, &ctask->headbuf, (u8*)ctask->hdrext);
        if (iscsi_sendhdr(conn, &ctask->headbuf, ctask->imm_count)) {
                ctask->xmstate |= XMSTATE_W_HDR;
@@ -1809,7 +1780,8 @@ handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                        return -EAGAIN;
                }
                if (conn->datadgst_en)
-                       iscsi_buf_data_digest_update(conn, &ctask->sendbuf);
+                       crypto_digest_update(conn->data_tx_tfm,
+                                            &ctask->sendbuf.sg, 1);
 
                if (!ctask->imm_count)
                        break;
@@ -1894,7 +1866,8 @@ handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
                 * so pass it
                 */
                if (conn->datadgst_en && ctask->sent - start > 0)
-                       iscsi_buf_data_digest_update(conn, &ctask->sendbuf);
+                       crypto_digest_update(conn->data_tx_tfm,
+                                            &ctask->sendbuf.sg, 1);
 
                if (!ctask->data_count)
                        break;
@@ -1972,7 +1945,7 @@ solicit_again:
 
        BUG_ON(r2t->data_count < 0);
        if (conn->datadgst_en)
-               iscsi_buf_data_digest_update(conn, &r2t->sendbuf);
+               crypto_digest_update(conn->data_tx_tfm, &r2t->sendbuf.sg, 1);
 
        if (r2t->data_count) {
                BUG_ON(ctask->sc->use_sg == 0);
@@ -2054,7 +2027,7 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
        }
 
        if (conn->datadgst_en) {
-               iscsi_buf_data_digest_update(conn, &ctask->sendbuf);
+               crypto_digest_update(conn->data_tx_tfm, &ctask->sendbuf.sg, 1);
                /* imm data? */
                if (!dtask) {
                        if (iscsi_digest_final_send(conn, ctask, &ctask->immbuf,
@@ -2148,7 +2121,7 @@ unsolicit_head_again:
 solicit_head_again:
                r2t = ctask->r2t;
                if (conn->hdrdgst_en)
-                       iscsi_hdr_digest(conn, &r2t->headbuf, 
+                       iscsi_hdr_digest(conn, &r2t->headbuf,
                                        (u8*)r2t->dtask->hdrext);
                if (iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count)) {
                        ctask->xmstate &= ~XMSTATE_SOL_DATA;
@@ -2300,10 +2273,10 @@ iscsi_xmitworker(void *data)
        /*
         * serialize Xmit worker on a per-connection basis.
         */
-       down(&conn->xmitsema);
+       mutex_lock(&conn->xmitmutex);
        if (iscsi_data_xmit(conn))
-               schedule_work(&conn->xmitwork);
-       up(&conn->xmitsema);
+               scsi_queue_work(conn->session->host, &conn->xmitwork);
+       mutex_unlock(&conn->xmitmutex);
 }
 
 #define FAILURE_BAD_HOST               1
@@ -2367,15 +2340,7 @@ iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
                session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
        spin_unlock(&session->lock);
 
-        if (!in_interrupt() && !down_trylock(&conn->xmitsema)) {
-               spin_unlock_irq(host->host_lock);
-               if (iscsi_data_xmit(conn))
-                       schedule_work(&conn->xmitwork);
-               up(&conn->xmitsema);
-               spin_lock_irq(host->host_lock);
-       } else
-               schedule_work(&conn->xmitwork);
-
+       scsi_queue_work(host, &conn->xmitwork);
        return 0;
 
 reject:
@@ -2462,17 +2427,20 @@ iscsi_pool_free(struct iscsi_queue *q, void **items)
        kfree(items);
 }
 
-static iscsi_connh_t
-iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx)
+static struct iscsi_cls_conn *
+iscsi_conn_create(struct Scsi_Host *shost, uint32_t conn_idx)
 {
-       struct iscsi_session *session = iscsi_ptr(sessionh);
-       struct iscsi_conn *conn = NULL;
+       struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+       struct iscsi_conn *conn;
+       struct iscsi_cls_conn *cls_conn;
 
-       conn = kmalloc(sizeof(struct iscsi_conn), GFP_KERNEL);
-       if (conn == NULL)
-               goto conn_alloc_fail;
-       memset(conn, 0, sizeof(struct iscsi_conn));
+       cls_conn = iscsi_create_conn(hostdata_session(shost->hostdata),
+                                    conn_idx);
+       if (!cls_conn)
+               return NULL;
+       conn = cls_conn->dd_data;
 
+       memset(conn, 0, sizeof(struct iscsi_conn));
        conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
        conn->in_progress = IN_PROGRESS_WAIT_HEADER;
        conn->id = conn_idx;
@@ -2531,10 +2499,10 @@ iscsi_conn_create(iscsi_sessionh_t sessionh, uint32_t conn_idx)
                goto max_recv_dlenght_alloc_fail;
 
        init_timer(&conn->tmabort_timer);
-       init_MUTEX(&conn->xmitsema);
+       mutex_init(&conn->xmitmutex);
        init_waitqueue_head(&conn->ehwait);
 
-       return iscsi_handle(conn);
+       return cls_conn;
 
 max_recv_dlenght_alloc_fail:
        spin_lock_bh(&session->lock);
@@ -2550,18 +2518,18 @@ immqueue_alloc_fail:
 writequeue_alloc_fail:
        kfifo_free(conn->xmitqueue);
 xmitqueue_alloc_fail:
-       kfree(conn);
-conn_alloc_fail:
-       return iscsi_handle(NULL);
+       iscsi_destroy_conn(cls_conn);
+       return NULL;
 }
 
 static void
-iscsi_conn_destroy(iscsi_connh_t connh)
+iscsi_conn_destroy(struct iscsi_cls_conn *cls_conn)
 {
-       struct iscsi_conn *conn = iscsi_ptr(connh);
+       struct iscsi_conn *conn = cls_conn->dd_data;
        struct iscsi_session *session = conn->session;
+       unsigned long flags;
 
-       down(&conn->xmitsema);
+       mutex_lock(&conn->xmitmutex);
        set_bit(SUSPEND_BIT, &conn->suspend_tx);
        if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE && conn->sock) {
                struct sock *sk = conn->sock->sk;
@@ -2592,19 +2560,19 @@ iscsi_conn_destroy(iscsi_connh_t connh)
        }
        spin_unlock_bh(&session->lock);
 
-       up(&conn->xmitsema);
+       mutex_unlock(&conn->xmitmutex);
 
        /*
         * Block until all in-progress commands for this connection
         * time out or fail.
         */
        for (;;) {
-               spin_lock_bh(&conn->lock);
+               spin_lock_irqsave(session->host->host_lock, flags);
                if (!session->host->host_busy) { /* OK for ERL == 0 */
-                       spin_unlock_bh(&conn->lock);
+                       spin_unlock_irqrestore(session->host->host_lock, flags);
                        break;
                }
-               spin_unlock_bh(&conn->lock);
+               spin_unlock_irqrestore(session->host->host_lock, flags);
                msleep_interruptible(500);
                printk("conn_destroy(): host_busy %d host_failed %d\n",
                        session->host->host_busy, session->host->host_failed);
@@ -2652,7 +2620,8 @@ iscsi_conn_destroy(iscsi_connh_t connh)
        kfifo_free(conn->writequeue);
        kfifo_free(conn->immqueue);
        kfifo_free(conn->mgmtqueue);
-       kfree(conn);
+
+       iscsi_destroy_conn(cls_conn);
 }
 
 static int
@@ -2713,6 +2682,8 @@ iscsi_conn_bind(iscsi_sessionh_t sessionh, iscsi_connh_t connh,
                 */
                iscsi_conn_set_callbacks(conn);
 
+               conn->sendpage = conn->sock->ops->sendpage;
+
                /*
                 * set receive state machine into initial state
                 */
@@ -2796,7 +2767,7 @@ iscsi_conn_stop(iscsi_connh_t connh, int flag)
        set_bit(SUSPEND_BIT, &conn->suspend_rx);
        write_unlock_bh(&sk->sk_callback_lock);
 
-       down(&conn->xmitsema);
+       mutex_lock(&conn->xmitmutex);
 
        spin_lock_irqsave(session->host->host_lock, flags);
        spin_lock(&session->lock);
@@ -2878,7 +2849,7 @@ iscsi_conn_stop(iscsi_connh_t connh, int flag)
                        conn->datadgst_en = 0;
                }
        }
-       up(&conn->xmitsema);
+       mutex_unlock(&conn->xmitmutex);
 }
 
 static int
@@ -2963,8 +2934,7 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        else
                __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
 
-       schedule_work(&conn->xmitwork);
-
+       scsi_queue_work(session->host, &conn->xmitwork);
        return 0;
 }
 
@@ -3029,12 +2999,12 @@ iscsi_eh_abort(struct scsi_cmnd *sc)
         * 1) connection-level failure;
         * 2) recovery due protocol error;
         */
-       down(&conn->xmitsema);
+       mutex_lock(&conn->xmitmutex);
        spin_lock_bh(&session->lock);
        if (session->state != ISCSI_STATE_LOGGED_IN) {
                if (session->state == ISCSI_STATE_TERMINATE) {
                        spin_unlock_bh(&session->lock);
-                       up(&conn->xmitsema);
+                       mutex_unlock(&conn->xmitmutex);
                        goto failed;
                }
                spin_unlock_bh(&session->lock);
@@ -3052,7 +3022,7 @@ iscsi_eh_abort(struct scsi_cmnd *sc)
                         * 2) session was re-open during time out of ctask.
                         */
                        spin_unlock_bh(&session->lock);
-                       up(&conn->xmitsema);
+                       mutex_unlock(&conn->xmitmutex);
                        goto success;
                }
                conn->tmabort_state = TMABORT_INITIAL;
@@ -3107,7 +3077,7 @@ iscsi_eh_abort(struct scsi_cmnd *sc)
                                    conn->tmabort_state == TMABORT_SUCCESS) {
                                        conn->tmabort_state = TMABORT_INITIAL;
                                        spin_unlock_bh(&session->lock);
-                                       up(&conn->xmitsema);
+                                       mutex_unlock(&conn->xmitmutex);
                                        goto success;
                                }
                                conn->tmabort_state = TMABORT_INITIAL;
@@ -3116,7 +3086,7 @@ iscsi_eh_abort(struct scsi_cmnd *sc)
                        spin_unlock_bh(&session->lock);
                }
        }
-       up(&conn->xmitsema);
+       mutex_unlock(&conn->xmitmutex);
 
 
        /*
@@ -3182,7 +3152,7 @@ failed:
 exit:
        del_timer_sync(&conn->tmabort_timer);
 
-       down(&conn->xmitsema);
+       mutex_lock(&conn->xmitmutex);
        if (conn->sock) {
                struct sock *sk = conn->sock->sk;
 
@@ -3190,7 +3160,7 @@ exit:
                iscsi_ctask_cleanup(conn, ctask);
                write_unlock_bh(&sk->sk_callback_lock);
        }
-       up(&conn->xmitsema);
+       mutex_unlock(&conn->xmitmutex);
        return rc;
 }
 
@@ -3281,17 +3251,23 @@ static struct scsi_host_template iscsi_sht = {
        .this_id                = -1,
 };
 
-static iscsi_sessionh_t
-iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host)
+static struct iscsi_transport iscsi_tcp_transport;
+
+static struct Scsi_Host *
+iscsi_session_create(struct scsi_transport_template *scsit,
+                    uint32_t initial_cmdsn)
 {
-       int cmd_i;
+       struct Scsi_Host *shost;
        struct iscsi_session *session;
+       int cmd_i;
 
-       session = iscsi_hostdata(host->hostdata);
-       memset(session, 0, sizeof(struct iscsi_session));
+       shost = iscsi_transport_create_session(scsit, &iscsi_tcp_transport);
+       if (!shost)
+               return NULL; 
 
-       session->host = host;
-       session->id = host->host_no;
+       session = iscsi_hostdata(shost->hostdata);
+       memset(session, 0, sizeof(struct iscsi_session));
+       session->host = shost;
        session->state = ISCSI_STATE_LOGGED_IN;
        session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
        session->cmds_max = ISCSI_XMIT_CMDS_MAX;
@@ -3335,7 +3311,7 @@ iscsi_session_create(uint32_t initial_cmdsn, struct Scsi_Host *host)
        if (iscsi_r2tpool_alloc(session))
                goto r2tpool_alloc_fail;
 
-       return iscsi_handle(session);
+       return shost;
 
 r2tpool_alloc_fail:
        for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++)
@@ -3345,15 +3321,15 @@ immdata_alloc_fail:
 mgmtpool_alloc_fail:
        iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
 cmdpool_alloc_fail:
-       return iscsi_handle(NULL);
+       return NULL;
 }
 
 static void
-iscsi_session_destroy(iscsi_sessionh_t sessionh)
+iscsi_session_destroy(struct Scsi_Host *shost)
 {
+       struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
        int cmd_i;
        struct iscsi_data_task *dtask, *n;
-       struct iscsi_session *session = iscsi_ptr(sessionh);
 
        for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) {
                struct iscsi_cmd_task *ctask = session->cmds[cmd_i];
@@ -3369,6 +3345,8 @@ iscsi_session_destroy(iscsi_sessionh_t sessionh)
        iscsi_r2tpool_free(session);
        iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
        iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+
+       iscsi_transport_destroy_session(shost);
 }
 
 static int
@@ -3467,6 +3445,8 @@ iscsi_conn_set_param(iscsi_connh_t connh, enum iscsi_param param,
                        if (conn->data_rx_tfm)
                                crypto_free_tfm(conn->data_rx_tfm);
                }
+               conn->sendpage = conn->datadgst_en ?
+                       sock_no_sendpage : conn->sock->ops->sendpage;
                break;
        case ISCSI_PARAM_INITIAL_R2T_EN:
                session->initial_r2t_en = value;
@@ -3515,25 +3495,12 @@ iscsi_conn_set_param(iscsi_connh_t connh, enum iscsi_param param,
 }
 
 static int
-iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param,
-                    uint32_t *value)
+iscsi_session_get_param(struct Scsi_Host *shost,
+                       enum iscsi_param param, uint32_t *value)
 {
-       struct iscsi_conn *conn = iscsi_ptr(connh);
-       struct iscsi_session *session = conn->session;
+       struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 
        switch(param) {
-       case ISCSI_PARAM_MAX_RECV_DLENGTH:
-               *value = conn->max_recv_dlength;
-               break;
-       case ISCSI_PARAM_MAX_XMIT_DLENGTH:
-               *value = conn->max_xmit_dlength;
-               break;
-       case ISCSI_PARAM_HDRDGST_EN:
-               *value = conn->hdrdgst_en;
-               break;
-       case ISCSI_PARAM_DATADGST_EN:
-               *value = conn->datadgst_en;
-               break;
        case ISCSI_PARAM_INITIAL_R2T_EN:
                *value = session->initial_r2t_en;
                break;
@@ -3571,6 +3538,31 @@ iscsi_conn_get_param(iscsi_connh_t connh, enum iscsi_param param,
        return 0;
 }
 
+static int
+iscsi_conn_get_param(void *data, enum iscsi_param param, uint32_t *value)
+{
+       struct iscsi_conn *conn = data;
+
+       switch(param) {
+       case ISCSI_PARAM_MAX_RECV_DLENGTH:
+               *value = conn->max_recv_dlength;
+               break;
+       case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+               *value = conn->max_xmit_dlength;
+               break;
+       case ISCSI_PARAM_HDRDGST_EN:
+               *value = conn->hdrdgst_en;
+               break;
+       case ISCSI_PARAM_DATADGST_EN:
+               *value = conn->datadgst_en;
+               break;
+       default:
+               return ISCSI_ERR_PARAM_NOT_FOUND;
+       }
+
+       return 0;
+}
+
 static void
 iscsi_conn_get_stats(iscsi_connh_t connh, struct iscsi_stats *stats)
 {
@@ -3601,9 +3593,9 @@ iscsi_conn_send_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr, char *data,
        struct iscsi_conn *conn = iscsi_ptr(connh);
        int rc;
 
-       down(&conn->xmitsema);
+       mutex_lock(&conn->xmitmutex);
        rc = iscsi_conn_send_generic(conn, hdr, data, data_size);
-       up(&conn->xmitsema);
+       mutex_unlock(&conn->xmitmutex);
 
        return rc;
 }
@@ -3615,6 +3607,7 @@ static struct iscsi_transport iscsi_tcp_transport = {
                                  | CAP_DATADGST,
        .host_template          = &iscsi_sht,
        .hostdata_size          = sizeof(struct iscsi_session),
+       .conndata_size          = sizeof(struct iscsi_conn),
        .max_conn               = 1,
        .max_cmd_len            = ISCSI_TCP_MAX_CMD_LEN,
        .create_session         = iscsi_session_create,
@@ -3623,7 +3616,8 @@ static struct iscsi_transport iscsi_tcp_transport = {
        .bind_conn              = iscsi_conn_bind,
        .destroy_conn           = iscsi_conn_destroy,
        .set_param              = iscsi_conn_set_param,
-       .get_param              = iscsi_conn_get_param,
+       .get_conn_param         = iscsi_conn_get_param,
+       .get_session_param      = iscsi_session_get_param,
        .start_conn             = iscsi_conn_start,
        .stop_conn              = iscsi_conn_stop,
        .send_pdu               = iscsi_conn_send_pdu,
@@ -3633,8 +3627,6 @@ static struct iscsi_transport iscsi_tcp_transport = {
 static int __init
 iscsi_tcp_init(void)
 {
-       int error;
-
        if (iscsi_max_lun < 1) {
                printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
                return -EINVAL;
@@ -3647,11 +3639,10 @@ iscsi_tcp_init(void)
        if (!taskcache)
                return -ENOMEM;
 
-       error = iscsi_register_transport(&iscsi_tcp_transport);
-       if (error)
+       if (!iscsi_register_transport(&iscsi_tcp_transport))
                kmem_cache_destroy(taskcache);
 
-       return error;
+       return 0;
 }
 
 static void __exit
index 855f2dfd18afb9612b84754130162c6f8ed559a1..f95e61b76f70baf3ba5bdd45906439db5971c4ba 100644 (file)
@@ -158,7 +158,7 @@ struct iscsi_conn {
        struct kfifo            *mgmtqueue;     /* mgmt (control) xmit queue */
        struct kfifo            *xmitqueue;     /* data-path cmd queue */
        struct work_struct      xmitwork;       /* per-conn. xmit workqueue */
-       struct semaphore        xmitsema;       /* serializes connection xmit,
+       struct mutex            xmitmutex;      /* serializes connection xmit,
                                                 * access to kfifos:      *
                                                 * xmitqueue, writequeue, *
                                                 * immqueue, mgmtqueue    */
@@ -191,6 +191,8 @@ struct iscsi_conn {
        uint32_t                sendpage_failures_cnt;
        uint32_t                discontiguous_hdr_cnt;
        uint32_t                eh_abort_cnt;
+
+       ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
 };
 
 struct iscsi_session {
@@ -240,8 +242,8 @@ struct iscsi_session {
 
 struct iscsi_buf {
        struct scatterlist      sg;
-       struct kvec             iov;
        unsigned int            sent;
+       char                    use_sendmsg;
 };
 
 struct iscsi_data_task {
index f55b9b3f7b37f1e8b4ad71e8c9950d8a1f3a9797..99bae8369ab294b3983517a799b3e1738bcc762d 100644 (file)
@@ -1747,7 +1747,7 @@ static const struct {
        { ATA_SHIFT_PIO,        XFER_PIO_0 },
 };
 
-static inline u8 base_from_shift(unsigned int shift)
+static u8 base_from_shift(unsigned int shift)
 {
        int i;
 
index 9ee8218404c058bc44e40157c891ad6464c2a605..dafabeefc5b3589de869a1c63b0703bfe512270a 100644 (file)
@@ -150,7 +150,7 @@ lpfc_new_scsi_buf(struct lpfc_hba * phba)
        return psb;
 }
 
-struct  lpfc_scsi_buf*
+static struct lpfc_scsi_buf*
 lpfc_get_scsi_buf(struct lpfc_hba * phba)
 {
        struct  lpfc_scsi_buf * lpfc_cmd = NULL;
index 4a6feb1e5e3d1249748cff23b770eb86412bb156..d101a8a6f4e86f4206bd3f70697af1f3506158ff 100644 (file)
@@ -4479,7 +4479,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
         * serialized. This is so because we want to reserve maximum number of
         * available command ids for the I/O commands.
         */
-       down(&adapter->int_mtx);
+       mutex_lock(&adapter->int_mtx);
 
        scb = &adapter->int_scb;
        memset(scb, 0, sizeof(scb_t));
@@ -4527,7 +4527,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
                        mc->cmd, mc->opcode, mc->subopcode, scmd->result);
        }
 
-       up(&adapter->int_mtx);
+       mutex_unlock(&adapter->int_mtx);
 
        return rval;
 }
@@ -4866,7 +4866,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
                adapter->has_64bit_addr = 0;
        }
                
-       init_MUTEX(&adapter->int_mtx);
+       mutex_init(&adapter->int_mtx);
        init_completion(&adapter->int_waitq);
 
        adapter->this_id = DEFAULT_INITIATOR_ID;
index 6f9078025748dcf681b4caf5a3aa59a4459c6430..4b3e0d6e5afacc6fbc05ae1085b2c02fcbe9fb28 100644 (file)
@@ -2,7 +2,7 @@
 #define __MEGARAID_H__
 
 #include <linux/spinlock.h>
-
+#include <linux/mutex.h>
 
 #define MEGARAID_VERSION       \
        "v2.00.3 (Release Date: Wed Feb 19 08:51:30 EST 2003)\n"
@@ -889,7 +889,7 @@ typedef struct {
 
        scb_t                   int_scb;
        Scsi_Cmnd               int_scmd;
-       struct semaphore        int_mtx;        /* To synchronize the internal
+       struct mutex            int_mtx;        /* To synchronize the internal
                                                commands */
        struct completion       int_waitq;      /* wait queue for internal
                                                 cmds */
index d18a4bc2498c5271be970ed2c9d8d77dee0e6a28..bf9f7f7ba354862467c11ca54fc40775056b4af9 100644 (file)
@@ -1266,7 +1266,7 @@ megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
  * return the scb from the head of the free list. NULL if there are none
  * available
  **/
-static inline scb_t *
+static scb_t *
 megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
 {
        struct list_head        *head = &adapter->kscb_pool;
@@ -1329,7 +1329,7 @@ megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
  *
  * prepare the scatter-gather list
  */
-static inline int
+static int
 megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
 {
        struct scatterlist      *sgl;
@@ -1402,7 +1402,7 @@ megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
  *
  * post the command to the controller if mailbox is availble.
  */
-static inline int
+static int
 mbox_post_cmd(adapter_t *adapter, scb_t *scb)
 {
        mraid_device_t  *raid_dev = ADAP2RAIDDEV(adapter);
@@ -2070,7 +2070,7 @@ megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
  *
  * Returns:    1 if the interrupt is valid, 0 otherwise
  */
-static inline int
+static int
 megaraid_ack_sequence(adapter_t *adapter)
 {
        mraid_device_t          *raid_dev = ADAP2RAIDDEV(adapter);
@@ -2208,7 +2208,7 @@ megaraid_isr(int irq, void *devp, struct pt_regs *regs)
  *
  * DMA sync if required.
  */
-static inline void
+static void
 megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
 {
        mbox_ccb_t      *ccb;
index 3c32e69afcd9e0dc691c2e76de94cd661b737b92..511ed52a580747be705be11e3f1d9dce325af7c8 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/uaccess.h>
 #include <linux/fs.h>
 #include <linux/compat.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -72,7 +73,7 @@ MODULE_DEVICE_TABLE(pci, megasas_pci_table);
 static int megasas_mgmt_majorno;
 static struct megasas_mgmt_info megasas_mgmt_info;
 static struct fasync_struct *megasas_async_queue;
-static DECLARE_MUTEX(megasas_async_queue_mutex);
+static DEFINE_MUTEX(megasas_async_queue_mutex);
 
 /**
  * megasas_get_cmd -   Get a command from the free pool
@@ -80,7 +81,7 @@ static DECLARE_MUTEX(megasas_async_queue_mutex);
  *
  * Returns a free command from the pool
  */
-static inline struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+static struct megasas_cmd *megasas_get_cmd(struct megasas_instance
                                                  *instance)
 {
        unsigned long flags;
@@ -262,7 +263,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
  * If successful, this function returns the number of SG elements. Otherwise,
  * it returnes -1.
  */
-static inline int
+static int
 megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
                   union megasas_sgl *mfi_sgl)
 {
@@ -310,7 +311,7 @@ megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * If successful, this function returns the number of SG elements. Otherwise,
  * it returnes -1.
  */
-static inline int
+static int
 megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
                   union megasas_sgl *mfi_sgl)
 {
@@ -359,7 +360,7 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * This function prepares CDB commands. These are typcially pass-through
  * commands to the devices.
  */
-static inline int
+static int
 megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
                   struct megasas_cmd *cmd)
 {
@@ -440,7 +441,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
  *
  * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
  */
-static inline int
+static int
 megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
                   struct megasas_cmd *cmd)
 {
@@ -562,7 +563,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * @scp:               SCSI command
  * @frame_count:       [OUT] Number of frames used to prepare this command
  */
-static inline struct megasas_cmd *megasas_build_cmd(struct megasas_instance
+static struct megasas_cmd *megasas_build_cmd(struct megasas_instance
                                                    *instance,
                                                    struct scsi_cmnd *scp,
                                                    int *frame_count)
@@ -913,7 +914,7 @@ megasas_complete_abort(struct megasas_instance *instance,
  * @instance:                  Adapter soft state
  * @cmd:                       Completed command
  */
-static inline void
+static void
 megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
 {
        dma_addr_t buf_h;
@@ -957,7 +958,7 @@ megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
  *                             an alternate status (as in the case of aborted
  *                             commands)
  */
-static inline void
+static void
 megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                     u8 alt_status)
 {
@@ -1104,7 +1105,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
  *                                     SCSI mid-layer instead of the status
  *                                     returned by the FW
  */
-static inline int
+static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
        u32 status;
@@ -2362,11 +2363,11 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
 {
        int rc;
 
-       down(&megasas_async_queue_mutex);
+       mutex_lock(&megasas_async_queue_mutex);
 
        rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
 
-       up(&megasas_async_queue_mutex);
+       mutex_unlock(&megasas_async_queue_mutex);
 
        if (rc >= 0) {
                /* For sanity check when we get ioctl */
index 5205c4e7d6fffb84c5608b2d687c195831322694..5758b2566d7f55e779040a5c89167af8c96a43bd 100644 (file)
@@ -1,4 +1,4 @@
-config SCSI_QLA2XXX
+config SCSI_QLA_FC
        tristate "QLogic QLA2XXX Fibre Channel Support"
        depends on PCI && SCSI
        select SCSI_FC_ATTRS
@@ -22,49 +22,57 @@ config SCSI_QLA2XXX
        Upon request, the driver caches the firmware image until
        the driver is unloaded.
 
+       Firmware images can be retrieved from:
+
+               ftp://ftp.qlogic.com/outgoing/linux/firmware/
+
        NOTE: The original method of building firmware-loader
        modules has been deprecated as the firmware-images will
        be removed from the kernel sources.
 
 config SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        bool "  Use firmware-loader modules (DEPRECATED)"
-       depends on SCSI_QLA2XXX
+       depends on SCSI_QLA_FC
+       help
+         This option offers you the deprecated firmware-loader
+         modules that have been obsoleted by the usage of the
+         Firmware Loader interface in the qla2xxx driver.
 
 config SCSI_QLA21XX
        tristate "  Build QLogic ISP2100 firmware-module"
-       depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+       depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        ---help---
        This driver supports the QLogic 21xx (ISP2100) host adapter family.
 
 config SCSI_QLA22XX
        tristate "  Build QLogic ISP2200 firmware-module"
-       depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+       depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        ---help---
        This driver supports the QLogic 22xx (ISP2200) host adapter family.
 
 config SCSI_QLA2300
        tristate "  Build QLogic ISP2300 firmware-module"
-       depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+       depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        ---help---
        This driver supports the QLogic 2300 (ISP2300 and ISP2312) host
        adapter family.
 
 config SCSI_QLA2322
        tristate "  Build QLogic ISP2322 firmware-module"
-       depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+       depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        ---help---
        This driver supports the QLogic 2322 (ISP2322) host adapter family.
 
 config SCSI_QLA6312
        tristate "  Build QLogic ISP63xx firmware-module"
-       depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+       depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        ---help---
        This driver supports the QLogic 63xx (ISP6312 and ISP6322) host
        adapter family.
 
 config SCSI_QLA24XX
        tristate "  Build QLogic ISP24xx firmware-module"
-       depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
+       depends on SCSI_QLA_FC && SCSI_QLA2XXX_EMBEDDED_FIRMWARE
        ---help---
        This driver supports the QLogic 24xx (ISP2422 and ISP2432) host
        adapter family.
index 40c0de1258897966413cad237debe24377769aa7..d028bc50ccf770664a3eb40df6cd9e28a8927674 100644 (file)
@@ -3,7 +3,7 @@ EXTRA_CFLAGS += -DUNIQUE_FW_NAME
 qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
                qla_dbg.o qla_sup.o qla_rscn.o qla_attr.o
 
-obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx.o
+obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
 
 qla2100-y := ql2100.o ql2100_fw.o
 qla2200-y := ql2200.o ql2200_fw.o
index 2efca52dff50c45629b82c6a9d3c3a2ea137d497..b17ee62dd1a9ce67981d5bfc4ebf6ce2e7596898 100644 (file)
@@ -541,7 +541,7 @@ struct fc_function_template qla2xxx_transport_functions = {
 void
 qla2x00_init_host_attr(scsi_qla_host_t *ha)
 {
-       fc_host_node_name(ha->host) = wwn_to_u64(ha->init_cb->node_name);
-       fc_host_port_name(ha->host) = wwn_to_u64(ha->init_cb->port_name);
+       fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
+       fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
        fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
 }
index 5c5d2315cfab2073b0fdaf892e83e4f477b9bfc2..2d9b12ffe09c3b9f85ecdd2d2f03d19dc91aa2d7 100644 (file)
@@ -1003,10 +1003,10 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
        fw = (struct qla24xx_fw_dump *) ha->fw_dump24;
 
        rval = QLA_SUCCESS;
-       fw->hccr = RD_REG_DWORD(&reg->hccr);
+       fw->host_status = RD_REG_DWORD(&reg->host_status);
 
        /* Pause RISC. */
-       if ((fw->hccr & HCCRX_RISC_PAUSE) == 0) {
+       if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
                WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
                    HCCRX_CLR_HOST_INT);
                RD_REG_DWORD(&reg->hccr);               /* PCI Posting. */
@@ -1021,16 +1021,54 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
                }
        }
 
-       /* Disable interrupts. */
-       WRT_REG_DWORD(&reg->ictrl, 0);
-       RD_REG_DWORD(&reg->ictrl);
-
        if (rval == QLA_SUCCESS) {
                /* Host interface registers. */
                dmp_reg = (uint32_t __iomem *)(reg + 0);
                for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
                        fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++);
 
+               /* Disable interrupts. */
+               WRT_REG_DWORD(&reg->ictrl, 0);
+               RD_REG_DWORD(&reg->ictrl);
+
+               /* Shadow registers. */
+               WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+               RD_REG_DWORD(&reg->iobase_addr);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0000000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg);
+
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0100000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg);
+
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0200000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg);
+
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0300000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg);
+
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0400000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg);
+
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0500000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg);
+
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
+               WRT_REG_DWORD(dmp_reg, 0xB0600000);
+               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
+               fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg);
+
                /* Mailbox registers. */
                mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
                for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
@@ -1308,43 +1346,6 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
                for (cnt = 0; cnt < 16; cnt++)
                        *iter_reg++ = RD_REG_DWORD(dmp_reg++);
 
-               WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-               RD_REG_DWORD(&reg->iobase_addr);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0000000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg);
-
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0100000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg);
-
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0200000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg);
-
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0300000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg);
-
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0400000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg);
-
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0500000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg);
-
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-               WRT_REG_DWORD(dmp_reg, 0xB0600000);
-               dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-               fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg);
-
                /* Local memory controller registers. */
                iter_reg = fw->lmc_reg;
                WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
@@ -1677,7 +1678,7 @@ qla24xx_ascii_fw_dump(scsi_qla_host_t *ha)
            ha->fw_major_version, ha->fw_minor_version,
            ha->fw_subminor_version, ha->fw_attributes);
 
-       qla_uprintf(&uiter, "\nHCCR Register\n%04x\n", fw->hccr);
+       qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status);
 
        qla_uprintf(&uiter, "\nHost Interface Registers");
        for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) {
@@ -1687,6 +1688,14 @@ qla24xx_ascii_fw_dump(scsi_qla_host_t *ha)
                qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]);
        }
 
+       qla_uprintf(&uiter, "\n\nShadow Registers");
+       for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) {
+               if (cnt % 8 == 0)
+                       qla_uprintf(&uiter, "\n");
+
+               qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]);
+       }
+
        qla_uprintf(&uiter, "\n\nMailbox Registers");
        for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) {
                if (cnt % 8 == 0)
@@ -1855,14 +1864,6 @@ qla24xx_ascii_fw_dump(scsi_qla_host_t *ha)
                qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]);
        }
 
-       qla_uprintf(&uiter, "\n\nShadow Registers");
-       for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) {
-               if (cnt % 8 == 0)
-                       qla_uprintf(&uiter, "\n");
-
-               qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]);
-       }
-
        qla_uprintf(&uiter, "\n\nLMC Registers");
        for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) {
                if (cnt % 8 == 0)
index 935a59a8c05455743b2820e9b79e2d0ab8f0d949..ab6afeaa2f2cafe79555b5d154f17c59b8e7b714 100644 (file)
@@ -227,8 +227,9 @@ struct qla2100_fw_dump {
 #define FW_DUMP_SIZE_24XX      0x2B0000
 
 struct qla24xx_fw_dump {
-       uint32_t hccr;
+       uint32_t host_status;
        uint32_t host_reg[32];
+       uint32_t shadow_reg[7];
        uint16_t mailbox_reg[32];
        uint32_t xseq_gp_reg[128];
        uint32_t xseq_0_reg[16];
@@ -250,7 +251,6 @@ struct qla24xx_fw_dump {
        uint32_t rcvt0_data_dma_reg[32];
        uint32_t rcvt1_data_dma_reg[32];
        uint32_t risc_gp_reg[128];
-       uint32_t shadow_reg[7];
        uint32_t lmc_reg[112];
        uint32_t fpm_hdw_reg[192];
        uint32_t fb_hdw_reg[176];
index bec81adcf4fd7938f07417b39c26ce4c1d921c47..32be4c14cccb50044a77b1c53b5b9be1eb5cc81d 100644 (file)
@@ -62,6 +62,7 @@ extern int qlport_down_retry;
 extern int ql2xplogiabsentdevice;
 extern int ql2xloginretrycount;
 extern int ql2xfdmienable;
+extern int ql2xprocessrscn;
 
 extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
 
@@ -96,10 +97,7 @@ int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
  * Global Function Prototypes in qla_mbx.c source file.
  */
 extern int
-qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t);
-
-extern int
-qla2x00_load_ram_ext(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
+qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
 
 extern int
 qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
index cd6f7c3cfe6887f92ce72e5e696b42e19d891429..d620a8e8a614c96b3ea60aca0ad9ec863563be7d 100644 (file)
@@ -538,6 +538,7 @@ qla2x00_rff_id(scsi_qla_host_t *ha)
        ct_req->req.rff_id.port_id[1] = ha->d_id.b.area;
        ct_req->req.rff_id.port_id[2] = ha->d_id.b.al_pa;
 
+       ct_req->req.rff_id.fc4_feature = BIT_1;
        ct_req->req.rff_id.fc4_type = 0x08;             /* SCSI - FCP */
 
        /* Execute MS IOCB */
@@ -1529,9 +1530,9 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
        eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
        eiter->len = __constant_cpu_to_be16(4 + 4);
        if (IS_QLA25XX(ha))
-               eiter->a.sup_speed = __constant_cpu_to_be32(4);
-       else if (IS_QLA24XX(ha))
                eiter->a.sup_speed = __constant_cpu_to_be32(8);
+       else if (IS_QLA24XX(ha))
+               eiter->a.sup_speed = __constant_cpu_to_be32(4);
        else if (IS_QLA23XX(ha))
                eiter->a.sup_speed = __constant_cpu_to_be32(2);
        else
@@ -1553,9 +1554,6 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
                eiter->a.cur_speed = __constant_cpu_to_be32(2);
                break;
        case 3:
-               eiter->a.cur_speed = __constant_cpu_to_be32(8);
-               break;
-       case 4:
                eiter->a.cur_speed = __constant_cpu_to_be32(4);
                break;
        }
index 7d973bd9022bb84773a11aa490ed39df1608133a..a91fea69ad63597b938b9afde16260ebb358d476 100644 (file)
@@ -1014,11 +1014,13 @@ qla24xx_update_fw_options(scsi_qla_host_t *ha)
        int rval;
 
        /* Update Serial Link options. */
-       if ((ha->fw_seriallink_options24[0] & BIT_0) == 0)
+       if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
                return;
 
-       rval = qla2x00_set_serdes_params(ha, ha->fw_seriallink_options24[1],
-           ha->fw_seriallink_options24[2], ha->fw_seriallink_options24[3]);
+       rval = qla2x00_set_serdes_params(ha,
+           le16_to_cpu(ha->fw_seriallink_options24[1]),
+           le16_to_cpu(ha->fw_seriallink_options24[2]),
+           le16_to_cpu(ha->fw_seriallink_options24[3]));
        if (rval != QLA_SUCCESS) {
                qla_printk(KERN_WARNING, ha,
                    "Unable to update Serial Link options (%x).\n", rval);
@@ -1939,6 +1941,9 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
                            "information -- get_port_database=%x, "
                            "loop_id=0x%04x\n",
                            ha->host_no, rval2, new_fcport->loop_id));
+                       DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
+                           ha->host_no));
+                       set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
                        continue;
                }
 
@@ -2648,7 +2653,8 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
 
                switch (format) {
                case 0:
-                       if (!IS_QLA2100(ha) && !IS_QLA2200(ha) &&
+                       if (ql2xprocessrscn &&
+                           !IS_QLA2100(ha) && !IS_QLA2200(ha) &&
                            !IS_QLA6312(ha) && !IS_QLA6322(ha) &&
                            !IS_QLA24XX(ha) && !IS_QLA25XX(ha) &&
                            ha->flags.init_done) {
@@ -3402,6 +3408,8 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
        ha->node_name = icb->node_name;
        ha->port_name = icb->port_name;
 
+       icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+
        ha->retry_count = le16_to_cpu(nv->login_retry_count);
 
        /* Set minimum login_timeout to 4 seconds. */
@@ -3667,8 +3675,8 @@ qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
                        for (i = 0; i < dlen; i++)
                                dcode[i] = swab32(dcode[i]);
 
-                       rval = qla2x00_load_ram_ext(ha, ha->request_dma,
-                           risc_addr, dlen);
+                       rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
+                           dlen);
                        if (rval) {
                                DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
                                    "segment %d of firmware\n", ha->host_no,
@@ -3868,8 +3876,8 @@ qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
                        for (i = 0; i < dlen; i++)
                                dcode[i] = swab32(fwcode[i]);
 
-                       rval = qla2x00_load_ram_ext(ha, ha->request_dma,
-                           risc_addr, dlen);
+                       rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
+                           dlen);
                        if (rval) {
                                DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
                                    "segment %d of firmware\n", ha->host_no,
index 5181d966fecba13be29a57c8d1c7e7cc84b753f4..f63af081d4ff8aaf219e2255e06e7a0c334f7c09 100644 (file)
@@ -519,7 +519,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
                 * us, create a new entry in our rscn fcports list and handle
                 * the event like an RSCN.
                 */
-               if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA6312(ha) &&
+               if (ql2xprocessrscn &&
+                   !IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA6312(ha) &&
                    !IS_QLA6322(ha) && !IS_QLA24XX(ha) && !IS_QLA25XX(ha) &&
                    ha->flags.init_done && mb[1] != 0xffff &&
                    ((ha->operating_mode == P2P && mb[1] != 0) ||
@@ -963,15 +964,16 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
                break;
 
        case CS_DATA_UNDERRUN:
-               DEBUG2(printk(KERN_INFO
-                   "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x.\n",
-                   ha->host_no, cp->device->id, cp->device->lun, comp_status,
-                   scsi_status));
-
                resid = resid_len;
                if (scsi_status & SS_RESIDUAL_UNDER) {
                        cp->resid = resid;
                        CMD_RESID_LEN(cp) = resid;
+               } else {
+                       DEBUG2(printk(KERN_INFO
+                           "scsi(%ld:%d:%d) UNDERRUN status detected "
+                           "0x%x-0x%x.\n", ha->host_no, cp->device->id,
+                           cp->device->lun, comp_status, scsi_status));
+
                }
 
                /*
index 9746cd1e664bd70429021ba77d68d5f071dd5c50..3099b379de9d89d554ebd1b5e9dde9d21fdb5d47 100644 (file)
@@ -196,7 +196,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
                        /* Check for pending interrupts. */
                        qla2x00_poll(ha);
 
-                       udelay(10); /* v4.27 */
+                       if (command != MBC_LOAD_RISC_RAM_EXTENDED &&
+                           !ha->flags.mbox_int)
+                               msleep(10);
                } /* while */
        }
 
@@ -325,113 +327,30 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
        return rval;
 }
 
-/*
- * qla2x00_load_ram
- *     Load adapter RAM using DMA.
- *
- * Input:
- *     ha = adapter block pointer.
- *
- * Returns:
- *     qla2x00 local function return status code.
- *
- * Context:
- *     Kernel context.
- */
 int
-qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint16_t risc_addr,
-    uint16_t risc_code_size)
+qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr,
+    uint32_t risc_code_size)
 {
        int rval;
        mbx_cmd_t mc;
        mbx_cmd_t *mcp = &mc;
-       uint32_t        req_len;
-       dma_addr_t      nml_dma;
-       uint32_t        nml_len;
-       uint32_t        normalized;
-
-       DEBUG11(printk("qla2x00_load_ram(%ld): entered.\n",
-           ha->host_no);)
 
-       req_len = risc_code_size;
-       nml_dma = 0;
-       nml_len = 0;
-
-       normalized = qla2x00_normalize_dma_addr(&req_dma, &req_len, &nml_dma,
-           &nml_len);
-
-       /* Load first segment */
-       mcp->mb[0] = MBC_LOAD_RISC_RAM;
-       mcp->mb[1] = risc_addr;
-       mcp->mb[2] = MSW(req_dma);
-       mcp->mb[3] = LSW(req_dma);
-       mcp->mb[4] = (uint16_t)req_len;
-       mcp->mb[6] = MSW(MSD(req_dma));
-       mcp->mb[7] = LSW(MSD(req_dma));
-       mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-       mcp->in_mb = MBX_0;
-       mcp->tov = 30;
-       mcp->flags = 0;
-       rval = qla2x00_mailbox_command(ha, mcp);
-
-       /* Load second segment - if necessary */
-       if (normalized && (rval == QLA_SUCCESS)) {
-               mcp->mb[0] = MBC_LOAD_RISC_RAM;
-               mcp->mb[1] = risc_addr + (uint16_t)req_len;
-               mcp->mb[2] = MSW(nml_dma);
-               mcp->mb[3] = LSW(nml_dma);
-               mcp->mb[4] = (uint16_t)nml_len;
-               mcp->mb[6] = MSW(MSD(nml_dma));
-               mcp->mb[7] = LSW(MSD(nml_dma));
-               mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
-               mcp->in_mb = MBX_0;
-               mcp->tov = 30;
-               mcp->flags = 0;
-               rval = qla2x00_mailbox_command(ha, mcp);
-       }
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-       if (rval == QLA_SUCCESS) {
-               /* Empty */
-               DEBUG11(printk("qla2x00_load_ram(%ld): done.\n", ha->host_no);)
+       if (MSW(risc_addr) || IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+               mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
+               mcp->mb[8] = MSW(risc_addr);
+               mcp->out_mb = MBX_8|MBX_0;
        } else {
-               /* Empty */
-               DEBUG2_3_11(printk("qla2x00_load_ram(%ld): failed. rval=%x "
-                   "mb[0]=%x.\n", ha->host_no, rval, mcp->mb[0]);)
+               mcp->mb[0] = MBC_LOAD_RISC_RAM;
+               mcp->out_mb = MBX_0;
        }
-       return rval;
-}
-
-/*
- * qla2x00_load_ram_ext
- *     Load adapter extended RAM using DMA.
- *
- * Input:
- *     ha = adapter block pointer.
- *
- * Returns:
- *     qla2x00 local function return status code.
- *
- * Context:
- *     Kernel context.
- */
-int
-qla2x00_load_ram_ext(scsi_qla_host_t *ha, dma_addr_t req_dma,
-    uint32_t risc_addr, uint32_t risc_code_size)
-{
-       int rval;
-       mbx_cmd_t mc;
-       mbx_cmd_t *mcp = &mc;
-
-       DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
-
-       mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
        mcp->mb[1] = LSW(risc_addr);
        mcp->mb[2] = MSW(req_dma);
        mcp->mb[3] = LSW(req_dma);
        mcp->mb[6] = MSW(MSD(req_dma));
        mcp->mb[7] = LSW(MSD(req_dma));
-       mcp->mb[8] = MSW(risc_addr);
-       mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
        if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
                mcp->mb[4] = MSW(risc_code_size);
                mcp->mb[5] = LSW(risc_code_size);
index 24304300d7b57b1fa359cd73660636590702e1b4..4916847d84ec9321a58629c0eef15543e73d2873 100644 (file)
@@ -71,6 +71,12 @@ MODULE_PARM_DESC(ql2xfdmienable,
                "Enables FDMI registratons "
                "Default is 0 - no FDMI. 1 - perfom FDMI.");
 
+int ql2xprocessrscn;
+module_param(ql2xprocessrscn, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xprocessrscn,
+               "Option to enable port RSCN handling via a series of less"
+               "fabric intrusive ADISCs and PLOGIs.");
+
 /*
  * SCSI host template entry points
  */
index d54d2a99c3d353545da80de30d4ad4705c1aebdb..f4d755a643e44d985d0378b06e6c134930da531f 100644 (file)
@@ -573,6 +573,9 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
                }
        } while (0);
 
+       /* Enable flash write-protection. */
+       qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
+
        /* Disable flash write. */
        WRT_REG_DWORD(&reg->ctrl_status,
            RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
index f7937f7f9c680cf4d373cc08aea9d915f3aa82f8..d537192a1edbe6f48e06a249d84ea01b780c2a2b 100644 (file)
@@ -7,9 +7,9 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.01.03-k"
+#define QLA2XXX_VERSION      "8.01.04-k"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   1
-#define QLA_DRIVER_PATCH_VER   3
+#define QLA_DRIVER_PATCH_VER   4
 #define QLA_DRIVER_BETA_VER    0
index 5ec5f44602ac8ebd7d18aa1865523fc4873233df..50c398aab5575305fc725f4e8e8b819b3abfce37 100644 (file)
@@ -148,9 +148,11 @@ static struct {
        { RAID_LEVEL_LINEAR, "linear" },
        { RAID_LEVEL_0, "raid0" },
        { RAID_LEVEL_1, "raid1" },
+       { RAID_LEVEL_10, "raid10" },
        { RAID_LEVEL_3, "raid3" },
        { RAID_LEVEL_4, "raid4" },
        { RAID_LEVEL_5, "raid5" },
+       { RAID_LEVEL_50, "raid50" },
        { RAID_LEVEL_6, "raid6" },
 };
 
index ee5f4dfdab149b7d5a52bf9d624d862c6d82233c..245ca99a641eb6432ee14434500531d36675fb22 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
+#include <linux/mutex.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -209,7 +210,7 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
        .gfp_mask       = __GFP_DMA,
 };
 
-static DECLARE_MUTEX(host_cmd_pool_mutex);
+static DEFINE_MUTEX(host_cmd_pool_mutex);
 
 static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
                                            gfp_t gfp_mask)
@@ -330,7 +331,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
         * Select a command slab for this host and create it if not
         * yet existant.
         */
-       down(&host_cmd_pool_mutex);
+       mutex_lock(&host_cmd_pool_mutex);
        pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
        if (!pool->users) {
                pool->slab = kmem_cache_create(pool->name,
@@ -342,7 +343,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
 
        pool->users++;
        shost->cmd_pool = pool;
-       up(&host_cmd_pool_mutex);
+       mutex_unlock(&host_cmd_pool_mutex);
 
        /*
         * Get one backup command for this host.
@@ -359,7 +360,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
                kmem_cache_destroy(pool->slab);
        return -ENOMEM;
  fail:
-       up(&host_cmd_pool_mutex);
+       mutex_unlock(&host_cmd_pool_mutex);
        return -ENOMEM;
 
 }
@@ -381,10 +382,10 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
                kmem_cache_free(shost->cmd_pool->slab, cmd);
        }
 
-       down(&host_cmd_pool_mutex);
+       mutex_lock(&host_cmd_pool_mutex);
        if (!--shost->cmd_pool->users)
                kmem_cache_destroy(shost->cmd_pool->slab);
-       up(&host_cmd_pool_mutex);
+       mutex_unlock(&host_cmd_pool_mutex);
 }
 
 #ifdef CONFIG_SCSI_LOGGING
index 3ded9daaf4a01c21732f7e7d4b3fb67d5e19fda4..0e529f8171c4123c98253e5035ede1b79d9cb1cf 100644 (file)
@@ -221,8 +221,6 @@ static struct bus_type pseudo_lld_bus;
 static struct device_driver sdebug_driverfs_driver = {
        .name           = sdebug_proc_name,
        .bus            = &pseudo_lld_bus,
-       .probe          = sdebug_driver_probe,
-       .remove         = sdebug_driver_remove,
 };
 
 static const int check_condition_result =
@@ -1796,6 +1794,8 @@ static int pseudo_lld_bus_match(struct device *dev,
 static struct bus_type pseudo_lld_bus = {
         .name = "pseudo",
         .match = pseudo_lld_bus_match,
+       .probe = sdebug_driver_probe,
+       .remove = sdebug_driver_remove,
 };
 
 static void sdebug_release_adapter(struct device * dev)
index 00c9bf383e2309f357ae0e23416c0b27557ebc53..3574ba935af8ea451741de17ae26b4e77087fe68 100644 (file)
@@ -1212,7 +1212,7 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
        return -EOPNOTSUPP;
 }
 
-static void scsi_generic_done(struct scsi_cmnd *cmd)
+static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
 {
        BUG_ON(!blk_pc_request(cmd->request));
        /*
@@ -1224,7 +1224,7 @@ static void scsi_generic_done(struct scsi_cmnd *cmd)
        scsi_io_completion(cmd, cmd->bufflen, 0);
 }
 
-void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
+static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
 {
        struct request *req = cmd->request;
 
@@ -1241,8 +1241,8 @@ void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
        cmd->transfersize = req->data_len;
        cmd->allowed = req->retries;
        cmd->timeout_per_command = req->timeout;
+       cmd->done = scsi_blk_pc_done;
 }
-EXPORT_SYMBOL_GPL(scsi_setup_blk_pc_cmnd);
 
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
@@ -1339,7 +1339,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
         * happening now.
         */
        if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-               struct scsi_driver *drv;
                int ret;
 
                /*
@@ -1371,16 +1370,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
                /*
                 * Initialize the actual SCSI command for this request.
                 */
-               if (req->rq_disk) {
+               if (req->flags & REQ_BLOCK_PC) {
+                       scsi_setup_blk_pc_cmnd(cmd);
+               } else if (req->rq_disk) {
+                       struct scsi_driver *drv;
+
                        drv = *(struct scsi_driver **)req->rq_disk->private_data;
                        if (unlikely(!drv->init_command(cmd))) {
                                scsi_release_buffers(cmd);
                                scsi_put_command(cmd);
                                goto kill;
                        }
-               } else {
-                       scsi_setup_blk_pc_cmnd(cmd);
-                       cmd->done = scsi_generic_done;
                }
        }
 
index 14a6198cb8d2b6ad3cf4635019a8f5caf8e5085b..27c48274e8cb11f1b26e2744699bdb4182116dae 100644 (file)
@@ -26,12 +26,6 @@ struct Scsi_Host;
 #define SCSI_SENSE_VALID(scmd) \
        (((scmd)->sense_buffer[0] & 0x70) == 0x70)
 
-/*
- * Special value for scanning to specify scanning or rescanning of all
- * possible channels, (target) ids, or luns on a given shost.
- */
-#define SCAN_WILD_CARD ~0
-
 /* hosts.c */
 extern int scsi_init_hosts(void);
 extern void scsi_exit_hosts(void);
index a50958b1b6eee68ab3fa17d8da7bc3639d8ff02a..07be62bbaaeac049a37cfa82aefad75d877de14d 100644 (file)
 #include <linux/errno.h>
 #include <linux/blkdev.h>
 #include <linux/seq_file.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -41,7 +43,7 @@
 static struct proc_dir_entry *proc_scsi;
 
 /* Protect sht->present and sht->proc_dir */
-static DECLARE_MUTEX(global_host_template_sem);
+static DEFINE_MUTEX(global_host_template_mutex);
 
 static int proc_scsi_read(char *buffer, char **start, off_t offset,
                          int length, int *eof, void *data)
@@ -83,7 +85,7 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
        if (!sht->proc_info)
                return;
 
-       down(&global_host_template_sem);
+       mutex_lock(&global_host_template_mutex);
        if (!sht->present++) {
                sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
                if (!sht->proc_dir)
@@ -92,7 +94,7 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
                else
                        sht->proc_dir->owner = sht->module;
        }
-       up(&global_host_template_sem);
+       mutex_unlock(&global_host_template_mutex);
 }
 
 void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
@@ -100,12 +102,12 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
        if (!sht->proc_info)
                return;
 
-       down(&global_host_template_sem);
+       mutex_lock(&global_host_template_mutex);
        if (!--sht->present && sht->proc_dir) {
                remove_proc_entry(sht->proc_name, proc_scsi);
                sht->proc_dir = NULL;
        }
-       up(&global_host_template_sem);
+       mutex_unlock(&global_host_template_mutex);
 }
 
 void scsi_proc_host_add(struct Scsi_Host *shost)
@@ -199,7 +201,10 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
        if (IS_ERR(shost))
                return PTR_ERR(shost);
 
-       error = scsi_scan_host_selected(shost, channel, id, lun, 1);
+       if (shost->transportt->user_scan)
+               error = shost->transportt->user_scan(shost, channel, id, lun);
+       else
+               error = scsi_scan_host_selected(shost, channel, id, lun, 1);
        scsi_host_put(shost);
        return error;
 }
index 05ebb9cef961534abd81120d8cc8c3422fc5cead..752fb5da3de4f55e461c2b93d3e3e108a2b2a89d 100644 (file)
@@ -334,19 +334,6 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
        struct scsi_target *starget;
        struct scsi_target *found_target;
 
-       /*
-        * Obtain the real parent from the transport. The transport
-        * is allowed to fail (no error) if there is nothing at that
-        * target id.
-        */
-       if (shost->transportt->target_parent) {
-               spin_lock_irqsave(shost->host_lock, flags);
-               parent = shost->transportt->target_parent(shost, channel, id);
-               spin_unlock_irqrestore(shost->host_lock, flags);
-               if (!parent)
-                       return NULL;
-       }
-
        starget = kmalloc(size, GFP_KERNEL);
        if (!starget) {
                printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
@@ -1283,20 +1270,21 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
        struct scsi_device *sdev;
        struct device *parent = &shost->shost_gendev;
        int res;
-       struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
+       struct scsi_target *starget;
 
+       starget = scsi_alloc_target(parent, channel, id);
        if (!starget)
                return ERR_PTR(-ENOMEM);
 
        get_device(&starget->dev);
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost)) {
                res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1,
                                             hostdata);
                if (res != SCSI_SCAN_LUN_PRESENT)
                        sdev = ERR_PTR(-ENODEV);
        }
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
        scsi_target_reap(starget);
        put_device(&starget->dev);
 
@@ -1404,10 +1392,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
 {
        struct Scsi_Host *shost = dev_to_shost(parent);
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost))
                __scsi_scan_target(parent, channel, id, lun, rescan);
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_scan_target);
 
@@ -1454,7 +1442,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
            ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
                return -EINVAL;
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (scsi_host_scan_allowed(shost)) {
                if (channel == SCAN_WILD_CARD)
                        for (channel = 0; channel <= shost->max_channel;
@@ -1464,7 +1452,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
                else
                        scsi_scan_channel(shost, channel, id, lun, rescan);
        }
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
 
        return 0;
 }
@@ -1522,7 +1510,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
        struct scsi_device *sdev = NULL;
        struct scsi_target *starget;
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        if (!scsi_host_scan_allowed(shost))
                goto out;
        starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
@@ -1536,7 +1524,7 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
        }
        put_device(&starget->dev);
  out:
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
        return sdev;
 }
 EXPORT_SYMBOL(scsi_get_host_dev);
index ea7f3a43357235f3287efe594e41f9799b2fa0aa..a77b32deaf8fdb732d45371a0eacf2c73a28d672 100644 (file)
@@ -106,7 +106,10 @@ static int scsi_scan(struct Scsi_Host *shost, const char *str)
                return -EINVAL;
        if (check_set(&lun, s3))
                return -EINVAL;
-       res = scsi_scan_host_selected(shost, channel, id, lun, 1);
+       if (shost->transportt->user_scan)
+               res = shost->transportt->user_scan(shost, channel, id, lun);
+       else
+               res = scsi_scan_host_selected(shost, channel, id, lun, 1);
        return res;
 }
 
@@ -745,9 +748,9 @@ void scsi_remove_device(struct scsi_device *sdev)
 {
        struct Scsi_Host *shost = sdev->host;
 
-       down(&shost->scan_mutex);
+       mutex_lock(&shost->scan_mutex);
        __scsi_remove_device(sdev);
-       up(&shost->scan_mutex);
+       mutex_unlock(&shost->scan_mutex);
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
index 685b997306cfcd4ca8758621e6e815d9d17da01c..f2c9acf11bd0c394084230718cfcbf48614d6e59 100644 (file)
@@ -295,6 +295,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
         */
        fc_host_node_name(shost) = -1;
        fc_host_port_name(shost) = -1;
+       fc_host_permanent_port_name(shost) = -1;
        fc_host_supported_classes(shost) = FC_COS_UNSPECIFIED;
        memset(fc_host_supported_fc4s(shost), 0,
                sizeof(fc_host_supported_fc4s(shost)));
@@ -795,6 +796,8 @@ static FC_CLASS_DEVICE_ATTR(host, supported_speeds, S_IRUGO,
 
 fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
 fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
+                            unsigned long long);
 fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
 fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
 fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
@@ -1090,17 +1093,23 @@ static int fc_rport_match(struct attribute_container *cont,
 /*
  * Must be called with shost->host_lock held
  */
-static struct device *fc_target_parent(struct Scsi_Host *shost,
-                                       int channel, uint id)
+static int fc_user_scan(struct Scsi_Host *shost, uint channel,
+               uint id, uint lun)
 {
        struct fc_rport *rport;
 
-       list_for_each_entry(rport, &fc_host_rports(shost), peers)
-               if ((rport->channel == channel) &&
-                   (rport->scsi_target_id == id))
-                       return &rport->dev;
+       list_for_each_entry(rport, &fc_host_rports(shost), peers) {
+               if (rport->scsi_target_id == -1)
+                       continue;
 
-       return NULL;
+               if ((channel == SCAN_WILD_CARD || channel == rport->channel) &&
+                   (id == SCAN_WILD_CARD || id == rport->scsi_target_id)) {
+                       scsi_scan_target(&rport->dev, rport->channel,
+                                        rport->scsi_target_id, lun, 1);
+               }
+       }
+
+       return 0;
 }
 
 struct scsi_transport_template *
@@ -1139,7 +1148,7 @@ fc_attach_transport(struct fc_function_template *ft)
        /* Transport uses the shost workq for scsi scanning */
        i->t.create_work_queue = 1;
 
-       i->t.target_parent = fc_target_parent;
+       i->t.user_scan = fc_user_scan;
        
        /*
         * Setup SCSI Target Attributes.
@@ -1160,6 +1169,7 @@ fc_attach_transport(struct fc_function_template *ft)
        count=0;
        SETUP_HOST_ATTRIBUTE_RD(node_name);
        SETUP_HOST_ATTRIBUTE_RD(port_name);
+       SETUP_HOST_ATTRIBUTE_RD(permanent_port_name);
        SETUP_HOST_ATTRIBUTE_RD(supported_classes);
        SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
        SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
index e08462d50c97e885305b218761407a74911b8f71..59a1c9d9d3bdc174eabed3553db658367288da44 100644 (file)
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 #include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
 #include <linux/mempool.h>
+#include <linux/mutex.h>
 #include <net/tcp.h>
-
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_device.h>
@@ -44,11 +42,6 @@ struct iscsi_internal {
         * List of sessions for this transport
         */
        struct list_head sessions;
-       /*
-        * lock to serialize access to the sessions list which must
-        * be taken after the rx_queue_sema
-        */
-       spinlock_t session_lock;
        /*
         * based on transport capabilities, at register time we set these
         * bits to tell the transport class it wants attributes displayed
@@ -70,7 +63,7 @@ struct iscsi_internal {
 /*
  * list of registered transports and lock that must
  * be held while accessing list. The iscsi_transport_lock must
- * be acquired after the rx_queue_sema.
+ * be acquired after the rx_queue_mutex.
  */
 static LIST_HEAD(iscsi_transports);
 static DEFINE_SPINLOCK(iscsi_transport_lock);
@@ -145,7 +138,7 @@ static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
 
 static struct sock *nls;
 static int daemon_pid;
-static DECLARE_MUTEX(rx_queue_sema);
+static DEFINE_MUTEX(rx_queue_mutex);
 
 struct mempool_zone {
        mempool_t *pool;
@@ -156,7 +149,7 @@ struct mempool_zone {
        spinlock_t freelock;
 };
 
-static struct mempool_zone z_reply;
+static struct mempool_zone *z_reply;
 
 /*
  * Z_MAX_* - actual mempool size allocated at the mempool_zone_init() time
@@ -171,50 +164,271 @@ static struct mempool_zone z_reply;
 #define Z_MAX_ERROR    16
 #define Z_HIWAT_ERROR  12
 
-struct iscsi_if_conn {
-       struct list_head conn_list;     /* item in connlist */
-       struct list_head session_list;  /* item in session->connections */
-       iscsi_connh_t connh;
-       int active;                     /* must be accessed with the connlock */
-       struct Scsi_Host *host;         /* originated shost */
-       struct device dev;              /* sysfs transport/container device */
-       struct iscsi_transport *transport;
-       struct mempool_zone z_error;
-       struct mempool_zone z_pdu;
-       struct list_head freequeue;
-};
+static LIST_HEAD(connlist);
+static DEFINE_SPINLOCK(connlock);
 
-#define iscsi_dev_to_if_conn(_dev) \
-       container_of(_dev, struct iscsi_if_conn, dev)
+/*
+ * The following functions can be used by LLDs that allocate
+ * their own scsi_hosts or by software iscsi LLDs
+ */
+static void iscsi_session_release(struct device *dev)
+{
+       struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
+       struct iscsi_transport *transport = session->transport;
+       struct Scsi_Host *shost;
 
-#define iscsi_cdev_to_if_conn(_cdev) \
-       iscsi_dev_to_if_conn(_cdev->dev)
+       shost = iscsi_session_to_shost(session);
+       scsi_host_put(shost);
+       kfree(session);
+       module_put(transport->owner);
+}
 
-static LIST_HEAD(connlist);
-static DEFINE_SPINLOCK(connlock);
+static int iscsi_is_session_dev(const struct device *dev)
+{
+       return dev->release == iscsi_session_release;
+}
 
-struct iscsi_if_session {
-       struct list_head list;  /* item in session_list */
-       struct list_head connections;
-       iscsi_sessionh_t sessionh;
-       struct iscsi_transport *transport;
-       struct device dev;      /* sysfs transport/container device */
-};
+/**
+ * iscsi_create_session - create iscsi class session
+ * @shost: scsi host
+ * @transport: iscsi transport
+ *
+ * This can be called from a LLD or iscsi_transport
+ **/
+struct iscsi_cls_session *
+iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport)
+{
+       struct iscsi_cls_session *session;
+       int err;
+
+       if (!try_module_get(transport->owner))
+               return NULL;
+
+       session = kzalloc(sizeof(*session), GFP_KERNEL);
+       if (!session)
+               goto module_put;
+       session->transport = transport;
+
+       /* this is released in the dev's release function */
+       scsi_host_get(shost);
+       snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no);
+       session->dev.parent = &shost->shost_gendev;
+       session->dev.release = iscsi_session_release;
+       err = device_register(&session->dev);
+       if (err) {
+               dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
+                          "register session's dev\n");
+               goto free_session;
+       }
+       transport_register_device(&session->dev);
+
+       return session;
+
+free_session:
+       kfree(session);
+module_put:
+       module_put(transport->owner);
+       return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_create_session);
+
+/**
+ * iscsi_destroy_session - destroy iscsi session
+ * @session: iscsi_session
+ *
+ * Can be called by a LLD or iscsi_transport. There must not be
+ * any running connections.
+ **/
+int iscsi_destroy_session(struct iscsi_cls_session *session)
+{
+       transport_unregister_device(&session->dev);
+       device_unregister(&session->dev);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_destroy_session);
+
+static void iscsi_conn_release(struct device *dev)
+{
+       struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
+       struct device *parent = conn->dev.parent;
+
+       kfree(conn);
+       put_device(parent);
+}
+
+static int iscsi_is_conn_dev(const struct device *dev)
+{
+       return dev->release == iscsi_conn_release;
+}
+
+/**
+ * iscsi_create_conn - create iscsi class connection
+ * @session: iscsi cls session
+ * @cid: connection id
+ *
+ * This can be called from a LLD or iscsi_transport. The connection
+ * is child of the session so cid must be unique for all connections
+ * on the session.
+ **/
+struct iscsi_cls_conn *
+iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
+{
+       struct iscsi_transport *transport = session->transport;
+       struct Scsi_Host *shost = iscsi_session_to_shost(session);
+       struct iscsi_cls_conn *conn;
+       int err;
+
+       conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL);
+       if (!conn)
+               return NULL;
+
+       if (transport->conndata_size)
+               conn->dd_data = &conn[1];
+
+       INIT_LIST_HEAD(&conn->conn_list);
+       conn->transport = transport;
+
+       /* this is released in the dev's release function */
+       if (!get_device(&session->dev))
+               goto free_conn;
+       snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
+                shost->host_no, cid);
+       conn->dev.parent = &session->dev;
+       conn->dev.release = iscsi_conn_release;
+       err = device_register(&conn->dev);
+       if (err) {
+               dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register "
+                          "connection's dev\n");
+               goto release_parent_ref;
+       }
+       transport_register_device(&conn->dev);
+       return conn;
+
+release_parent_ref:
+       put_device(&session->dev);
+free_conn:
+       kfree(conn);
+       return NULL;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_create_conn);
+
+/**
+ * iscsi_destroy_conn - destroy iscsi class connection
+ * @session: iscsi cls session
+ *
+ * This can be called from a LLD or iscsi_transport.
+ **/
+int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
+{
+       transport_unregister_device(&conn->dev);
+       device_unregister(&conn->dev);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_destroy_conn);
+
+/*
+ * These functions are used only by software iscsi_transports
+ * which do not allocate and more their scsi_hosts since this
+ * is initiated from userspace.
+ */
+
+/*
+ * iSCSI Session's hostdata organization:
+ *
+ *    *------------------* <== hostdata_session(host->hostdata)
+ *    | ptr to class sess|
+ *    |------------------| <== iscsi_hostdata(host->hostdata)
+ *    | transport's data |
+ *    *------------------*
+ */
+
+#define hostdata_privsize(_t)  (sizeof(unsigned long) + _t->hostdata_size + \
+                                _t->hostdata_size % sizeof(unsigned long))
+
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
+
+/**
+ * iscsi_transport_create_session - create iscsi cls session and host
+ * scsit: scsi transport template
+ * transport: iscsi transport template
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+struct Scsi_Host *
+iscsi_transport_create_session(struct scsi_transport_template *scsit,
+                              struct iscsi_transport *transport)
+{
+       struct iscsi_cls_session *session;
+       struct Scsi_Host *shost;
+
+       shost = scsi_host_alloc(transport->host_template,
+                               hostdata_privsize(transport));
+       if (!shost) {
+               printk(KERN_ERR "iscsi: can not allocate SCSI host for "
+                       "session\n");
+               return NULL;
+       }
+
+       shost->max_id = 1;
+       shost->max_channel = 0;
+       shost->max_lun = transport->max_lun;
+       shost->max_cmd_len = transport->max_cmd_len;
+       shost->transportt = scsit;
+       shost->transportt->create_work_queue = 1;
+
+       if (scsi_add_host(shost, NULL))
+               goto free_host;
+
+       session = iscsi_create_session(shost, transport);
+       if (!session)
+               goto remove_host;
 
-#define iscsi_dev_to_if_session(_dev) \
-       container_of(_dev, struct iscsi_if_session, dev)
+       *(unsigned long*)shost->hostdata = (unsigned long)session;
+       return shost;
+
+remove_host:
+       scsi_remove_host(shost);
+free_host:
+       scsi_host_put(shost);
+       return NULL;
+}
 
-#define iscsi_cdev_to_if_session(_cdev) \
-       iscsi_dev_to_if_session(_cdev->dev)
+EXPORT_SYMBOL_GPL(iscsi_transport_create_session);
 
-#define iscsi_if_session_to_shost(_session) \
-       dev_to_shost(_session->dev.parent)
+/**
+ * iscsi_transport_destroy_session - destroy session and scsi host
+ * shost: scsi host
+ *
+ * This can be used by software iscsi_transports that allocate
+ * a session per scsi host.
+ **/
+int iscsi_transport_destroy_session(struct Scsi_Host *shost)
+{
+       struct iscsi_cls_session *session;
 
-static struct iscsi_if_conn*
+       scsi_remove_host(shost);
+       session = hostdata_session(shost->hostdata);
+       iscsi_destroy_session(session);
+       /* ref from host alloc */
+       scsi_host_put(shost);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(iscsi_transport_destroy_session);
+
+/*
+ * iscsi interface functions
+ */
+static struct iscsi_cls_conn*
 iscsi_if_find_conn(uint64_t key)
 {
        unsigned long flags;
-       struct iscsi_if_conn *conn;
+       struct iscsi_cls_conn *conn;
 
        spin_lock_irqsave(&connlock, flags);
        list_for_each_entry(conn, &connlist, conn_list)
@@ -249,7 +463,7 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb)
 }
 
 static void*
-mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
+mempool_zone_alloc_skb(unsigned int gfp_mask, void *pool_data)
 {
        struct mempool_zone *zone = pool_data;
 
@@ -281,14 +495,21 @@ mempool_zone_complete(struct mempool_zone *zone)
        spin_unlock_irqrestore(&zone->freelock, flags);
 }
 
-static int
-mempool_zone_init(struct mempool_zone *zp, unsigned max, unsigned size,
-               unsigned hiwat)
+static struct mempool_zone *
+mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
 {
+       struct mempool_zone *zp;
+
+       zp = kzalloc(sizeof(*zp), GFP_KERNEL);
+       if (!zp)
+               return NULL;
+
        zp->pool = mempool_create(max, mempool_zone_alloc_skb,
                                  mempool_zone_free_skb, zp);
-       if (!zp->pool)
-               return -ENOMEM;
+       if (!zp->pool) {
+               kfree(zp);
+               return NULL;
+       }
 
        zp->size = size;
        zp->hiwat = hiwat;
@@ -297,9 +518,14 @@ mempool_zone_init(struct mempool_zone *zp, unsigned max, unsigned size,
        spin_lock_init(&zp->freelock);
        atomic_set(&zp->allocated, 0);
 
-       return 0;
+       return zp;
 }
 
+static void mempool_zone_destroy(struct mempool_zone *zp)
+{
+       mempool_destroy(zp->pool);
+       kfree(zp);
+}
 
 static struct sk_buff*
 mempool_zone_get_skb(struct mempool_zone *zone)
@@ -339,7 +565,7 @@ int iscsi_recv_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr,
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        struct iscsi_uevent *ev;
-       struct iscsi_if_conn *conn;
+       struct iscsi_cls_conn *conn;
        char *pdu;
        int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
                              data_size);
@@ -347,13 +573,13 @@ int iscsi_recv_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr,
        conn = iscsi_if_find_conn(connh);
        BUG_ON(!conn);
 
-       mempool_zone_complete(&conn->z_pdu);
+       mempool_zone_complete(conn->z_pdu);
 
-       skb = mempool_zone_get_skb(&conn->z_pdu);
+       skb = mempool_zone_get_skb(conn->z_pdu);
        if (!skb) {
                iscsi_conn_error(connh, ISCSI_ERR_CONN_FAILED);
-               printk(KERN_ERR "iscsi%d: can not deliver control PDU: OOM\n",
-                      conn->host->host_no);
+               dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver "
+                          "control PDU: OOM\n");
                return -ENOMEM;
        }
 
@@ -362,14 +588,14 @@ int iscsi_recv_pdu(iscsi_connh_t connh, struct iscsi_hdr *hdr,
        memset(ev, 0, sizeof(*ev));
        ev->transport_handle = iscsi_handle(conn->transport);
        ev->type = ISCSI_KEVENT_RECV_PDU;
-       if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat)
+       if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
                ev->iferror = -ENOMEM;
        ev->r.recv_req.conn_handle = connh;
        pdu = (char*)ev + sizeof(*ev);
        memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
        memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
 
-       return iscsi_unicast_skb(&conn->z_pdu, skb);
+       return iscsi_unicast_skb(conn->z_pdu, skb);
 }
 EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
 
@@ -378,18 +604,18 @@ void iscsi_conn_error(iscsi_connh_t connh, enum iscsi_err error)
        struct nlmsghdr *nlh;
        struct sk_buff  *skb;
        struct iscsi_uevent *ev;
-       struct iscsi_if_conn *conn;
+       struct iscsi_cls_conn *conn;
        int len = NLMSG_SPACE(sizeof(*ev));
 
        conn = iscsi_if_find_conn(connh);
        BUG_ON(!conn);
 
-       mempool_zone_complete(&conn->z_error);
+       mempool_zone_complete(conn->z_error);
 
-       skb = mempool_zone_get_skb(&conn->z_error);
+       skb = mempool_zone_get_skb(conn->z_error);
        if (!skb) {
-               printk(KERN_ERR "iscsi%d: gracefully ignored conn error (%d)\n",
-                      conn->host->host_no, error);
+               dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored "
+                         "conn error (%d)\n", error);
                return;
        }
 
@@ -397,15 +623,15 @@ void iscsi_conn_error(iscsi_connh_t connh, enum iscsi_err error)
        ev = NLMSG_DATA(nlh);
        ev->transport_handle = iscsi_handle(conn->transport);
        ev->type = ISCSI_KEVENT_CONN_ERROR;
-       if (atomic_read(&conn->z_error.allocated) >= conn->z_error.hiwat)
+       if (atomic_read(&conn->z_error->allocated) >= conn->z_error->hiwat)
                ev->iferror = -ENOMEM;
        ev->r.connerror.error = error;
        ev->r.connerror.conn_handle = connh;
 
-       iscsi_unicast_skb(&conn->z_error, skb);
+       iscsi_unicast_skb(conn->z_error, skb);
 
-       printk(KERN_INFO "iscsi%d: detected conn error (%d)\n",
-              conn->host->host_no, error);
+       dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
+                  error);
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_error);
 
@@ -419,9 +645,9 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
        int flags = multi ? NLM_F_MULTI : 0;
        int t = done ? NLMSG_DONE : type;
 
-       mempool_zone_complete(&z_reply);
+       mempool_zone_complete(z_reply);
 
-       skb = mempool_zone_get_skb(&z_reply);
+       skb = mempool_zone_get_skb(z_reply);
        /*
         * FIXME:
         * user is supposed to react on iferror == -ENOMEM;
@@ -432,366 +658,197 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
        nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
        nlh->nlmsg_flags = flags;
        memcpy(NLMSG_DATA(nlh), payload, size);
-       return iscsi_unicast_skb(&z_reply, skb);
+       return iscsi_unicast_skb(z_reply, skb);
 }
 
-/*
- * iSCSI Session's hostdata organization:
- *
- *    *------------------* <== host->hostdata
- *    | transport        |
- *    |------------------| <== iscsi_hostdata(host->hostdata)
- *    | transport's data |
- *    |------------------| <== hostdata_session(host->hostdata)
- *    | interface's data |
- *    *------------------*
- */
+static int
+iscsi_if_get_stats(struct iscsi_transport *transport, struct sk_buff *skb,
+                  struct nlmsghdr *nlh)
+{
+       struct iscsi_uevent *ev = NLMSG_DATA(nlh);
+       struct iscsi_stats *stats;
+       struct sk_buff *skbstat;
+       struct iscsi_cls_conn *conn;
+       struct nlmsghdr *nlhstat;
+       struct iscsi_uevent *evstat;
+       int len = NLMSG_SPACE(sizeof(*ev) +
+                             sizeof(struct iscsi_stats) +
+                             sizeof(struct iscsi_stats_custom) *
+                             ISCSI_STATS_CUSTOM_MAX);
+       int err = 0;
 
-#define hostdata_privsize(_t)  (sizeof(unsigned long) + _t->hostdata_size + \
-                                _t->hostdata_size % sizeof(unsigned long) + \
-                                sizeof(struct iscsi_if_session))
+       conn = iscsi_if_find_conn(ev->u.get_stats.conn_handle);
+       if (!conn)
+               return -EEXIST;
 
-#define hostdata_session(_hostdata) ((void*)_hostdata + sizeof(unsigned long) + \
-                       ((struct iscsi_transport *) \
-                        iscsi_ptr(*(uint64_t *)_hostdata))->hostdata_size)
+       do {
+               int actual_size;
 
-static void iscsi_if_session_dev_release(struct device *dev)
-{
-       struct iscsi_if_session *session = iscsi_dev_to_if_session(dev);
-       struct iscsi_transport *transport = session->transport;
-       struct Scsi_Host *shost = iscsi_if_session_to_shost(session);
-       struct iscsi_if_conn *conn, *tmp;
-       unsigned long flags;
+               mempool_zone_complete(conn->z_pdu);
 
-       /* now free connections */
-       spin_lock_irqsave(&connlock, flags);
-       list_for_each_entry_safe(conn, tmp, &session->connections,
-                                session_list) {
-               list_del(&conn->session_list);
-               mempool_destroy(conn->z_pdu.pool);
-               mempool_destroy(conn->z_error.pool);
-               kfree(conn);
-       }
-       spin_unlock_irqrestore(&connlock, flags);
-       scsi_host_put(shost);
-       module_put(transport->owner);
+               skbstat = mempool_zone_get_skb(conn->z_pdu);
+               if (!skbstat) {
+                       dev_printk(KERN_ERR, &conn->dev, "iscsi: can not "
+                                  "deliver stats: OOM\n");
+                       return -ENOMEM;
+               }
+
+               nlhstat = __nlmsg_put(skbstat, daemon_pid, 0, 0,
+                                     (len - sizeof(*nlhstat)), 0);
+               evstat = NLMSG_DATA(nlhstat);
+               memset(evstat, 0, sizeof(*evstat));
+               evstat->transport_handle = iscsi_handle(conn->transport);
+               evstat->type = nlh->nlmsg_type;
+               if (atomic_read(&conn->z_pdu->allocated) >= conn->z_pdu->hiwat)
+                       evstat->iferror = -ENOMEM;
+               evstat->u.get_stats.conn_handle =
+                       ev->u.get_stats.conn_handle;
+               stats = (struct iscsi_stats *)
+                       ((char*)evstat + sizeof(*evstat));
+               memset(stats, 0, sizeof(*stats));
+
+               transport->get_stats(ev->u.get_stats.conn_handle, stats);
+               actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
+                                         sizeof(struct iscsi_stats) +
+                                         sizeof(struct iscsi_stats_custom) *
+                                         stats->custom_length);
+               actual_size -= sizeof(*nlhstat);
+               actual_size = NLMSG_LENGTH(actual_size);
+               skb_trim(skb, NLMSG_ALIGN(actual_size));
+               nlhstat->nlmsg_len = actual_size;
+
+               err = iscsi_unicast_skb(conn->z_pdu, skbstat);
+       } while (err < 0 && err != -ECONNREFUSED);
+
+       return err;
 }
 
 static int
 iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
 {
        struct iscsi_transport *transport = priv->iscsi_transport;
-       struct iscsi_if_session *session;
        struct Scsi_Host *shost;
-       unsigned long flags;
-       int error;
-
-       if (!try_module_get(transport->owner))
-               return -EPERM;
 
-       shost = scsi_host_alloc(transport->host_template,
-                               hostdata_privsize(transport));
-       if (!shost) {
-               ev->r.c_session_ret.session_handle = iscsi_handle(NULL);
-               printk(KERN_ERR "iscsi: can not allocate SCSI host for "
-                      "session\n");
-               error = -ENOMEM;
-               goto out_module_put;
-       }
-       shost->max_id = 1;
-       shost->max_channel = 0;
-       shost->max_lun = transport->max_lun;
-       shost->max_cmd_len = transport->max_cmd_len;
-       shost->transportt = &priv->t;
-
-       /* store struct iscsi_transport in hostdata */
-       *(uint64_t*)shost->hostdata = ev->transport_handle;
+       if (!transport->create_session)
+               return -EINVAL;
 
-       ev->r.c_session_ret.session_handle = transport->create_session(
-                                       ev->u.c_session.initial_cmdsn, shost);
-       if (ev->r.c_session_ret.session_handle == iscsi_handle(NULL)) {
-               error = 0;
-               goto out_host_put;
-       }
+       shost = transport->create_session(&priv->t,
+                                         ev->u.c_session.initial_cmdsn);
+       if (!shost)
+               return -ENOMEM;
 
-       /* host_no becomes assigned SID */
+       ev->r.c_session_ret.session_handle = iscsi_handle(iscsi_hostdata(shost->hostdata));
        ev->r.c_session_ret.sid = shost->host_no;
-       /* initialize session */
-       session = hostdata_session(shost->hostdata);
-       INIT_LIST_HEAD(&session->connections);
-       INIT_LIST_HEAD(&session->list);
-       session->sessionh = ev->r.c_session_ret.session_handle;
-       session->transport = transport;
-
-       error = scsi_add_host(shost, NULL);
-       if (error)
-               goto out_destroy_session;
-
-       /*
-        * this is released in the dev's release function)
-        */
-       scsi_host_get(shost);
-       snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", shost->host_no);
-       session->dev.parent = &shost->shost_gendev;
-       session->dev.release = iscsi_if_session_dev_release;
-       error = device_register(&session->dev);
-       if (error) {
-               printk(KERN_ERR "iscsi: could not register session%d's dev\n",
-                      shost->host_no);
-               goto out_remove_host;
-       }
-       transport_register_device(&session->dev);
-
-       /* add this session to the list of active sessions */
-       spin_lock_irqsave(&priv->session_lock, flags);
-       list_add(&session->list, &priv->sessions);
-       spin_unlock_irqrestore(&priv->session_lock, flags);
-
        return 0;
-
-out_remove_host:
-       scsi_remove_host(shost);
-out_destroy_session:
-       transport->destroy_session(ev->r.c_session_ret.session_handle);
-       ev->r.c_session_ret.session_handle = iscsi_handle(NULL);
-out_host_put:
-       scsi_host_put(shost);
-out_module_put:
-       module_put(transport->owner);
-       return error;
 }
 
 static int
 iscsi_if_destroy_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
 {
        struct iscsi_transport *transport = priv->iscsi_transport;
+
        struct Scsi_Host *shost;
-       struct iscsi_if_session *session;
-       unsigned long flags;
-       struct iscsi_if_conn *conn;
-       int error = 0;
+
+       if (!transport->destroy_session)
+               return -EINVAL;
 
        shost = scsi_host_lookup(ev->u.d_session.sid);
        if (shost == ERR_PTR(-ENXIO))
                return -EEXIST;
-       session = hostdata_session(shost->hostdata);
 
-       /* check if we have active connections */
-       spin_lock_irqsave(&connlock, flags);
-       list_for_each_entry(conn, &session->connections, session_list) {
-               if (conn->active) {
-                       printk(KERN_ERR "iscsi%d: can not destroy session: "
-                              "has active connection (%p)\n",
-                              shost->host_no, iscsi_ptr(conn->connh));
-                       spin_unlock_irqrestore(&connlock, flags);
-                       error = EIO;
-                       goto out_release_ref;
-               }
-       }
-       spin_unlock_irqrestore(&connlock, flags);
-
-       scsi_remove_host(shost);
-       transport->destroy_session(ev->u.d_session.session_handle);
-       transport_unregister_device(&session->dev);
-       device_unregister(&session->dev);
-
-       /* remove this session from the list of active sessions */
-       spin_lock_irqsave(&priv->session_lock, flags);
-       list_del(&session->list);
-       spin_unlock_irqrestore(&priv->session_lock, flags);
-
-       /* ref from host alloc */
-       scsi_host_put(shost);
-out_release_ref:
-       /* ref from host lookup */
-       scsi_host_put(shost);
-       return error;
-}
-
-static void iscsi_if_conn_dev_release(struct device *dev)
-{
-       struct iscsi_if_conn *conn = iscsi_dev_to_if_conn(dev);
-       struct Scsi_Host *shost = conn->host;
-
-       scsi_host_put(shost);
+       if (transport->destroy_session)
+               transport->destroy_session(shost);
+        /* ref from host lookup */
+        scsi_host_put(shost);
+       return 0;
 }
 
 static int
-iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
-{
-       struct iscsi_if_session *session;
+iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev){
        struct Scsi_Host *shost;
-       struct iscsi_if_conn *conn;
+       struct iscsi_cls_conn *conn;
        unsigned long flags;
-       int error;
+
+       if (!transport->create_conn)
+               return -EINVAL;
 
        shost = scsi_host_lookup(ev->u.c_conn.sid);
        if (shost == ERR_PTR(-ENXIO))
                return -EEXIST;
-       session = hostdata_session(shost->hostdata);
 
-       conn = kmalloc(sizeof(struct iscsi_if_conn), GFP_KERNEL);
-       if (!conn) {
-               error = -ENOMEM;
-               goto out_release_ref;
-       }
-       memset(conn, 0, sizeof(struct iscsi_if_conn));
-       INIT_LIST_HEAD(&conn->session_list);
-       INIT_LIST_HEAD(&conn->conn_list);
-       conn->host = shost;
-       conn->transport = transport;
+       conn = transport->create_conn(shost, ev->u.c_conn.cid);
+       if (!conn)
+               goto release_ref;
 
-       error = mempool_zone_init(&conn->z_pdu, Z_MAX_PDU,
+       conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
                        NLMSG_SPACE(sizeof(struct iscsi_uevent) +
                                    sizeof(struct iscsi_hdr) +
                                    DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
                        Z_HIWAT_PDU);
-       if (error) {
-               printk(KERN_ERR "iscsi%d: can not allocate pdu zone for new "
-                      "conn\n", shost->host_no);
-               goto out_free_conn;
+       if (!conn->z_pdu) {
+               dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+                          "pdu zone for new conn\n");
+               goto destroy_conn;
        }
-       error = mempool_zone_init(&conn->z_error, Z_MAX_ERROR,
+
+       conn->z_error = mempool_zone_init(Z_MAX_ERROR,
                        NLMSG_SPACE(sizeof(struct iscsi_uevent)),
                        Z_HIWAT_ERROR);
-       if (error) {
-               printk(KERN_ERR "iscsi%d: can not allocate error zone for "
-                      "new conn\n", shost->host_no);
-               goto out_free_pdu_pool;
-       }
-
-       ev->r.handle = transport->create_conn(ev->u.c_conn.session_handle,
-                                       ev->u.c_conn.cid);
-       if (!ev->r.handle) {
-               error = -ENODEV;
-               goto out_free_error_pool;
+       if (!conn->z_error) {
+               dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+                          "error zone for new conn\n");
+               goto free_pdu_pool;
        }
 
-       conn->connh = ev->r.handle;
-
-       /*
-        * this is released in the dev's release function
-        */
-       if (!scsi_host_get(shost))
-               goto out_destroy_conn;
-       snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
-                shost->host_no, ev->u.c_conn.cid);
-       conn->dev.parent = &session->dev;
-       conn->dev.release = iscsi_if_conn_dev_release;
-       error = device_register(&conn->dev);
-       if (error) {
-               printk(KERN_ERR "iscsi%d: could not register connections%u "
-                      "dev\n", shost->host_no, ev->u.c_conn.cid);
-               goto out_release_parent_ref;
-       }
-       transport_register_device(&conn->dev);
+       ev->r.handle = conn->connh = iscsi_handle(conn->dd_data);
 
        spin_lock_irqsave(&connlock, flags);
        list_add(&conn->conn_list, &connlist);
-       list_add(&conn->session_list, &session->connections);
        conn->active = 1;
        spin_unlock_irqrestore(&connlock, flags);
 
        scsi_host_put(shost);
        return 0;
 
-out_release_parent_ref:
+free_pdu_pool:
+       mempool_zone_destroy(conn->z_pdu);
+destroy_conn:
+       if (transport->destroy_conn)
+               transport->destroy_conn(conn->dd_data);
+release_ref:
        scsi_host_put(shost);
-out_destroy_conn:
-       transport->destroy_conn(ev->r.handle);
-out_free_error_pool:
-       mempool_destroy(conn->z_error.pool);
-out_free_pdu_pool:
-       mempool_destroy(conn->z_pdu.pool);
-out_free_conn:
-       kfree(conn);
-out_release_ref:
-       scsi_host_put(shost);
-       return error;
+       return -ENOMEM;
 }
 
 static int
 iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
 {
        unsigned long flags;
-       struct iscsi_if_conn *conn;
+       struct iscsi_cls_conn *conn;
+       struct mempool_zone *z_error, *z_pdu;
 
        conn = iscsi_if_find_conn(ev->u.d_conn.conn_handle);
        if (!conn)
                return -EEXIST;
 
-       transport->destroy_conn(ev->u.d_conn.conn_handle);
+       if (!transport->destroy_conn)
+               return -EINVAL;
 
        spin_lock_irqsave(&connlock, flags);
        conn->active = 0;
        list_del(&conn->conn_list);
        spin_unlock_irqrestore(&connlock, flags);
 
-       transport_unregister_device(&conn->dev);
-       device_unregister(&conn->dev);
-       return 0;
-}
-
-static int
-iscsi_if_get_stats(struct iscsi_transport *transport, struct sk_buff *skb,
-                  struct nlmsghdr *nlh)
-{
-       struct iscsi_uevent *ev = NLMSG_DATA(nlh);
-       struct iscsi_stats *stats;
-       struct sk_buff *skbstat;
-       struct iscsi_if_conn *conn;
-       struct nlmsghdr *nlhstat;
-       struct iscsi_uevent *evstat;
-       int len = NLMSG_SPACE(sizeof(*ev) +
-                             sizeof(struct iscsi_stats) +
-                             sizeof(struct iscsi_stats_custom) *
-                             ISCSI_STATS_CUSTOM_MAX);
-       int err = 0;
-
-       conn = iscsi_if_find_conn(ev->u.get_stats.conn_handle);
-       if (!conn)
-               return -EEXIST;
-
-       do {
-               int actual_size;
-
-               mempool_zone_complete(&conn->z_pdu);
-
-               skbstat = mempool_zone_get_skb(&conn->z_pdu);
-               if (!skbstat) {
-                       printk(KERN_ERR "iscsi%d: can not deliver stats: OOM\n",
-                              conn->host->host_no);
-                       return -ENOMEM;
-               }
-
-               nlhstat = __nlmsg_put(skbstat, daemon_pid, 0, 0,
-                                     (len - sizeof(*nlhstat)), 0);
-               evstat = NLMSG_DATA(nlhstat);
-               memset(evstat, 0, sizeof(*evstat));
-               evstat->transport_handle = iscsi_handle(conn->transport);
-               evstat->type = nlh->nlmsg_type;
-               if (atomic_read(&conn->z_pdu.allocated) >= conn->z_pdu.hiwat)
-                       evstat->iferror = -ENOMEM;
-               evstat->u.get_stats.conn_handle =
-                       ev->u.get_stats.conn_handle;
-               stats = (struct iscsi_stats *)
-                       ((char*)evstat + sizeof(*evstat));
-               memset(stats, 0, sizeof(*stats));
+       z_pdu = conn->z_pdu;
+       z_error = conn->z_error;
 
-               transport->get_stats(ev->u.get_stats.conn_handle, stats);
-               actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
-                                         sizeof(struct iscsi_stats) +
-                                         sizeof(struct iscsi_stats_custom) *
-                                         stats->custom_length);
-               actual_size -= sizeof(*nlhstat);
-               actual_size = NLMSG_LENGTH(actual_size);
-               skb_trim(skb, NLMSG_ALIGN(actual_size));
-               nlhstat->nlmsg_len = actual_size;
+       if (transport->destroy_conn)
+               transport->destroy_conn(conn);
 
-               err = iscsi_unicast_skb(&conn->z_pdu, skbstat);
-       } while (err < 0 && err != -ECONNREFUSED);
+       mempool_zone_destroy(z_pdu);
+       mempool_zone_destroy(z_error);
 
-       return err;
+       return 0;
 }
 
 static int
@@ -881,7 +938,7 @@ iscsi_if_rx(struct sock *sk, int len)
 {
        struct sk_buff *skb;
 
-       down(&rx_queue_sema);
+       mutex_lock(&rx_queue_mutex);
        while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
                while (skb->len >= NLMSG_SPACE(0)) {
                        int err;
@@ -915,17 +972,20 @@ iscsi_if_rx(struct sock *sk, int len)
                                err = iscsi_if_send_reply(
                                        NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
                                        nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-                               if (atomic_read(&z_reply.allocated) >=
-                                               z_reply.hiwat)
+                               if (atomic_read(&z_reply->allocated) >=
+                                               z_reply->hiwat)
                                        ev->iferror = -ENOMEM;
                        } while (err < 0 && err != -ECONNREFUSED);
                        skb_pull(skb, rlen);
                }
                kfree_skb(skb);
        }
-       up(&rx_queue_sema);
+       mutex_unlock(&rx_queue_mutex);
 }
 
+#define iscsi_cdev_to_conn(_cdev) \
+       iscsi_dev_to_conn(_cdev->dev)
+
 /*
  * iSCSI connection attrs
  */
@@ -934,12 +994,10 @@ static ssize_t                                                            \
 show_conn_int_param_##param(struct class_device *cdev, char *buf)      \
 {                                                                      \
        uint32_t value = 0;                                             \
-       struct iscsi_if_conn *conn = iscsi_cdev_to_if_conn(cdev);       \
-       struct iscsi_internal *priv;                                    \
+       struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev);         \
+       struct iscsi_transport *t = conn->transport;                    \
                                                                        \
-       priv = to_iscsi_internal(conn->host->transportt);               \
-       if (priv->param_mask & (1 << param))                            \
-               priv->iscsi_transport->get_param(conn->connh, param, &value); \
+       t->get_conn_param(conn->dd_data, param, &value);                \
        return snprintf(buf, 20, format"\n", value);                    \
 }
 
@@ -954,6 +1012,9 @@ iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d");
 iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
 iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
 
+#define iscsi_cdev_to_session(_cdev) \
+       iscsi_dev_to_session(_cdev->dev)
+
 /*
  * iSCSI session attrs
  */
@@ -962,20 +1023,11 @@ static ssize_t                                                           \
 show_session_int_param_##param(struct class_device *cdev, char *buf)   \
 {                                                                      \
        uint32_t value = 0;                                             \
-       struct iscsi_if_session *session = iscsi_cdev_to_if_session(cdev); \
-       struct Scsi_Host *shost = iscsi_if_session_to_shost(session);   \
-       struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
-       struct iscsi_if_conn *conn = NULL;                              \
-       unsigned long  flags;                                           \
-                                                                       \
-       spin_lock_irqsave(&connlock, flags);                            \
-       if (!list_empty(&session->connections))                         \
-               conn = list_entry(session->connections.next,            \
-                                 struct iscsi_if_conn, session_list);  \
-       spin_unlock_irqrestore(&connlock, flags);                       \
+       struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);        \
+       struct Scsi_Host *shost = iscsi_session_to_shost(session);      \
+       struct iscsi_transport *t = session->transport;                 \
                                                                        \
-       if (conn && (priv->param_mask & (1 << param)))                  \
-               priv->iscsi_transport->get_param(conn->connh, param, &value);\
+       t->get_session_param(shost, param, &value);                     \
        return snprintf(buf, 20, format"\n", value);                    \
 }
 
@@ -1004,23 +1056,18 @@ iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d");
                count++;                                                \
        }
 
-static int iscsi_is_session_dev(const struct device *dev)
-{
-       return dev->release == iscsi_if_session_dev_release;
-}
-
 static int iscsi_session_match(struct attribute_container *cont,
                           struct device *dev)
 {
-       struct iscsi_if_session *session;
+       struct iscsi_cls_session *session;
        struct Scsi_Host *shost;
        struct iscsi_internal *priv;
 
        if (!iscsi_is_session_dev(dev))
                return 0;
 
-       session = iscsi_dev_to_if_session(dev);
-       shost = iscsi_if_session_to_shost(session);
+       session = iscsi_dev_to_session(dev);
+       shost = iscsi_session_to_shost(session);
        if (!shost->transportt)
                return 0;
 
@@ -1031,23 +1078,21 @@ static int iscsi_session_match(struct attribute_container *cont,
        return &priv->session_cont.ac == cont;
 }
 
-static int iscsi_is_conn_dev(const struct device *dev)
-{
-       return dev->release == iscsi_if_conn_dev_release;
-}
-
 static int iscsi_conn_match(struct attribute_container *cont,
                           struct device *dev)
 {
-       struct iscsi_if_conn *conn;
+       struct iscsi_cls_session *session;
+       struct iscsi_cls_conn *conn;
        struct Scsi_Host *shost;
        struct iscsi_internal *priv;
 
        if (!iscsi_is_conn_dev(dev))
                return 0;
 
-       conn = iscsi_dev_to_if_conn(dev);
-       shost = conn->host;
+       conn = iscsi_dev_to_conn(dev);
+       session = iscsi_dev_to_session(conn->dev.parent);
+       shost = iscsi_session_to_shost(session);
+
        if (!shost->transportt)
                return 0;
 
@@ -1058,7 +1103,8 @@ static int iscsi_conn_match(struct attribute_container *cont,
        return &priv->conn_cont.ac == cont;
 }
 
-int iscsi_register_transport(struct iscsi_transport *tt)
+struct scsi_transport_template *
+iscsi_register_transport(struct iscsi_transport *tt)
 {
        struct iscsi_internal *priv;
        unsigned long flags;
@@ -1068,15 +1114,14 @@ int iscsi_register_transport(struct iscsi_transport *tt)
 
        priv = iscsi_if_transport_lookup(tt);
        if (priv)
-               return -EEXIST;
+               return NULL;
 
        priv = kmalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
-               return -ENOMEM;
+               return NULL;
        memset(priv, 0, sizeof(*priv));
        INIT_LIST_HEAD(&priv->list);
        INIT_LIST_HEAD(&priv->sessions);
-       spin_lock_init(&priv->session_lock);
        priv->iscsi_transport = tt;
 
        priv->cdev.class = &iscsi_transport_class;
@@ -1142,13 +1187,13 @@ int iscsi_register_transport(struct iscsi_transport *tt)
        spin_unlock_irqrestore(&iscsi_transport_lock, flags);
 
        printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
-       return 0;
+       return &priv->t;
 
 unregister_cdev:
        class_device_unregister(&priv->cdev);
 free_priv:
        kfree(priv);
-       return err;
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(iscsi_register_transport);
 
@@ -1159,19 +1204,11 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
 
        BUG_ON(!tt);
 
-       down(&rx_queue_sema);
+       mutex_lock(&rx_queue_mutex);
 
        priv = iscsi_if_transport_lookup(tt);
        BUG_ON (!priv);
 
-       spin_lock_irqsave(&priv->session_lock, flags);
-       if (!list_empty(&priv->sessions)) {
-               spin_unlock_irqrestore(&priv->session_lock, flags);
-               up(&rx_queue_sema);
-               return -EPERM;
-       }
-       spin_unlock_irqrestore(&priv->session_lock, flags);
-
        spin_lock_irqsave(&iscsi_transport_lock, flags);
        list_del(&priv->list);
        spin_unlock_irqrestore(&iscsi_transport_lock, flags);
@@ -1181,7 +1218,7 @@ int iscsi_unregister_transport(struct iscsi_transport *tt)
 
        sysfs_remove_group(&priv->cdev.kobj, &iscsi_transport_group);
        class_device_unregister(&priv->cdev);
-       up(&rx_queue_sema);
+       mutex_unlock(&rx_queue_mutex);
 
        return 0;
 }
@@ -1194,14 +1231,14 @@ iscsi_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr)
 
        if (event == NETLINK_URELEASE &&
            n->protocol == NETLINK_ISCSI && n->pid) {
-               struct iscsi_if_conn *conn;
+               struct iscsi_cls_conn *conn;
                unsigned long flags;
 
-               mempool_zone_complete(&z_reply);
+               mempool_zone_complete(z_reply);
                spin_lock_irqsave(&connlock, flags);
                list_for_each_entry(conn, &connlist, conn_list) {
-                       mempool_zone_complete(&conn->z_error);
-                       mempool_zone_complete(&conn->z_pdu);
+                       mempool_zone_complete(conn->z_error);
+                       mempool_zone_complete(conn->z_pdu);
                }
                spin_unlock_irqrestore(&connlock, flags);
        }
@@ -1234,15 +1271,15 @@ static __init int iscsi_transport_init(void)
                goto unregister_session_class;
 
        nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
-                                   THIS_MODULE);
+                       THIS_MODULE);
        if (!nls) {
                err = -ENOBUFS;
                goto unregister_notifier;
        }
 
-       err = mempool_zone_init(&z_reply, Z_MAX_REPLY,
+       z_reply = mempool_zone_init(Z_MAX_REPLY,
                NLMSG_SPACE(sizeof(struct iscsi_uevent)), Z_HIWAT_REPLY);
-       if (!err)
+       if (z_reply)
                return 0;
 
        sock_release(nls->sk_socket);
@@ -1259,7 +1296,7 @@ unregister_transport_class:
 
 static void __exit iscsi_transport_exit(void)
 {
-       mempool_destroy(z_reply.pool);
+       mempool_zone_destroy(z_reply);
        sock_release(nls->sk_socket);
        netlink_unregister_notifier(&iscsi_nl_notifier);
        transport_class_unregister(&iscsi_connection_class);
index edabbd05d258882050661058b8bb32da15e69672..a3e0b7bc2d7bd1a71b31b0f4be0e091ae5b20b9b 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 
+#include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
@@ -62,7 +63,7 @@ struct sas_internal {
 
 struct sas_host_attrs {
        struct list_head rphy_list;
-       spinlock_t lock;
+       struct mutex lock;
        u32 next_target_id;
 };
 #define to_sas_host_attrs(host)        ((struct sas_host_attrs *)(host)->shost_data)
@@ -165,7 +166,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
        struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
        INIT_LIST_HEAD(&sas_host->rphy_list);
-       spin_lock_init(&sas_host->lock);
+       mutex_init(&sas_host->lock);
        sas_host->next_target_id = 0;
        return 0;
 }
@@ -626,7 +627,7 @@ int sas_rphy_add(struct sas_rphy *rphy)
        transport_add_device(&rphy->dev);
        transport_configure_device(&rphy->dev);
 
-       spin_lock(&sas_host->lock);
+       mutex_lock(&sas_host->lock);
        list_add_tail(&rphy->list, &sas_host->rphy_list);
        if (identify->device_type == SAS_END_DEVICE &&
            (identify->target_port_protocols &
@@ -634,10 +635,10 @@ int sas_rphy_add(struct sas_rphy *rphy)
                rphy->scsi_target_id = sas_host->next_target_id++;
        else
                rphy->scsi_target_id = -1;
-       spin_unlock(&sas_host->lock);
+       mutex_unlock(&sas_host->lock);
 
        if (rphy->scsi_target_id != -1) {
-               scsi_scan_target(&rphy->dev, parent->number,
+               scsi_scan_target(&rphy->dev, parent->port_identifier,
                                rphy->scsi_target_id, ~0, 0);
        }
 
@@ -661,9 +662,9 @@ void sas_rphy_free(struct sas_rphy *rphy)
        struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
        struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
-       spin_lock(&sas_host->lock);
+       mutex_lock(&sas_host->lock);
        list_del(&rphy->list);
-       spin_unlock(&sas_host->lock);
+       mutex_unlock(&sas_host->lock);
 
        transport_destroy_device(&rphy->dev);
        put_device(rphy->dev.parent);
@@ -687,15 +688,27 @@ sas_rphy_delete(struct sas_rphy *rphy)
        struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
        struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
-       scsi_remove_target(dev);
+       switch (rphy->identify.device_type) {
+       case SAS_END_DEVICE:
+               scsi_remove_target(dev);
+               break;
+       case SAS_EDGE_EXPANDER_DEVICE:
+       case SAS_FANOUT_EXPANDER_DEVICE:
+               device_for_each_child(dev, NULL, do_sas_phy_delete);
+               break;
+       default:
+               break;
+       }
 
        transport_remove_device(dev);
        device_del(dev);
        transport_destroy_device(dev);
 
-       spin_lock(&sas_host->lock);
+       mutex_lock(&sas_host->lock);
        list_del(&rphy->list);
-       spin_unlock(&sas_host->lock);
+       mutex_unlock(&sas_host->lock);
+
+       parent->rphy = NULL;
 
        put_device(&parent->dev);
 }
@@ -719,23 +732,28 @@ EXPORT_SYMBOL(scsi_is_sas_rphy);
  * SCSI scan helper
  */
 
-static struct device *sas_target_parent(struct Scsi_Host *shost,
-                                       int channel, uint id)
+static int sas_user_scan(struct Scsi_Host *shost, uint channel,
+               uint id, uint lun)
 {
        struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
        struct sas_rphy *rphy;
-       struct device *dev = NULL;
 
-       spin_lock(&sas_host->lock);
+       mutex_lock(&sas_host->lock);
        list_for_each_entry(rphy, &sas_host->rphy_list, list) {
                struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
-               if (parent->number == channel &&
-                   rphy->scsi_target_id == id)
-                       dev = &rphy->dev;
+
+               if (rphy->scsi_target_id == -1)
+                       continue;
+
+               if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
+                   (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
+                       scsi_scan_target(&rphy->dev, parent->port_identifier,
+                                        rphy->scsi_target_id, lun, 1);
+               }
        }
-       spin_unlock(&sas_host->lock);
+       mutex_unlock(&sas_host->lock);
 
-       return dev;
+       return 0;
 }
 
 
@@ -780,7 +798,7 @@ sas_attach_transport(struct sas_function_template *ft)
                return NULL;
        memset(i, 0, sizeof(struct sas_internal));
 
-       i->t.target_parent = sas_target_parent;
+       i->t.user_scan = sas_user_scan;
 
        i->t.host_attrs.ac.attrs = &i->host_attrs[0];
        i->t.host_attrs.ac.class = &sas_host_class.class;
index 46da6fe10ad54d1d25dc1784071365d8fe288287..7ee95eb83ddaa52c5fe1aa50a52642b150293eba 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/module.h>
 #include <linux/workqueue.h>
 #include <linux/blkdev.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <scsi/scsi.h>
 #include "scsi_priv.h"
 #include <scsi/scsi_device.h>
@@ -48,7 +48,7 @@
 
 /* Private data accessors (keep these out of the header file) */
 #define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
-#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
+#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
 
 struct spi_internal {
        struct scsi_transport_template t;
@@ -242,7 +242,7 @@ static int spi_setup_transport_attrs(struct transport_container *tc,
        spi_hold_mcs(starget) = 0;
        spi_dv_pending(starget) = 0;
        spi_initial_dv(starget) = 0;
-       init_MUTEX(&spi_dv_sem(starget));
+       mutex_init(&spi_dv_mutex(starget));
 
        return 0;
 }
@@ -915,7 +915,7 @@ spi_dv_device(struct scsi_device *sdev)
        scsi_target_quiesce(starget);
 
        spi_dv_pending(starget) = 1;
-       down(&spi_dv_sem(starget));
+       mutex_lock(&spi_dv_mutex(starget));
 
        starget_printk(KERN_INFO, starget, "Beginning Domain Validation\n");
 
@@ -923,7 +923,7 @@ spi_dv_device(struct scsi_device *sdev)
 
        starget_printk(KERN_INFO, starget, "Ending Domain Validation\n");
 
-       up(&spi_dv_sem(starget));
+       mutex_unlock(&spi_dv_mutex(starget));
        spi_dv_pending(starget) = 0;
 
        scsi_target_resume(starget);
@@ -1075,7 +1075,7 @@ static const char * const extended_msgs[] = {
 /* 0x04 */ "Parallel Protocol Request"
 };
 
-void print_nego(const unsigned char *msg, int per, int off, int width)
+static void print_nego(const unsigned char *msg, int per, int off, int width)
 {
        if (per) {
                char buf[20];
index 4c5127ed379c6560dd22e17e0aa408b7b51979f8..930db398d107f4b1a7310ee399a6ab7e692b89b6 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/blkpg.h>
 #include <linux/kref.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -111,7 +112,7 @@ static DEFINE_SPINLOCK(sd_index_lock);
 /* This semaphore is used to mediate the 0->1 reference get in the
  * face of object destruction (i.e. we can't allow a get on an
  * object after last put) */
-static DECLARE_MUTEX(sd_ref_sem);
+static DEFINE_MUTEX(sd_ref_mutex);
 
 static int sd_revalidate_disk(struct gendisk *disk);
 static void sd_rw_intr(struct scsi_cmnd * SCpnt);
@@ -193,9 +194,9 @@ static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
 {
        struct scsi_disk *sdkp;
 
-       down(&sd_ref_sem);
+       mutex_lock(&sd_ref_mutex);
        sdkp = __scsi_disk_get(disk);
-       up(&sd_ref_sem);
+       mutex_unlock(&sd_ref_mutex);
        return sdkp;
 }
 
@@ -203,11 +204,11 @@ static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev)
 {
        struct scsi_disk *sdkp;
 
-       down(&sd_ref_sem);
+       mutex_lock(&sd_ref_mutex);
        sdkp = dev_get_drvdata(dev);
        if (sdkp)
                sdkp = __scsi_disk_get(sdkp->disk);
-       up(&sd_ref_sem);
+       mutex_unlock(&sd_ref_mutex);
        return sdkp;
 }
 
@@ -215,10 +216,10 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
 {
        struct scsi_device *sdev = sdkp->device;
 
-       down(&sd_ref_sem);
+       mutex_lock(&sd_ref_mutex);
        kref_put(&sdkp->kref, scsi_disk_release);
        scsi_device_put(sdev);
-       up(&sd_ref_sem);
+       mutex_unlock(&sd_ref_mutex);
 }
 
 /**
@@ -231,34 +232,12 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
  **/
 static int sd_init_command(struct scsi_cmnd * SCpnt)
 {
-       unsigned int this_count, timeout;
-       struct gendisk *disk;
-       sector_t block;
        struct scsi_device *sdp = SCpnt->device;
        struct request *rq = SCpnt->request;
-
-       timeout = sdp->timeout;
-
-       /*
-        * SG_IO from block layer already setup, just copy cdb basically
-        */
-       if (blk_pc_request(rq)) {
-               scsi_setup_blk_pc_cmnd(SCpnt);
-               if (rq->timeout)
-                       timeout = rq->timeout;
-
-               goto queue;
-       }
-
-       /*
-        * we only do REQ_CMD and REQ_BLOCK_PC
-        */
-       if (!blk_fs_request(rq))
-               return 0;
-
-       disk = rq->rq_disk;
-       block = rq->sector;
-       this_count = SCpnt->request_bufflen >> 9;
+       struct gendisk *disk = rq->rq_disk;
+       sector_t block = rq->sector;
+       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,
@@ -401,8 +380,6 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
        SCpnt->transfersize = sdp->sector_size;
        SCpnt->underflow = this_count << 9;
        SCpnt->allowed = SD_MAX_RETRIES;
-
-queue:
        SCpnt->timeout_per_command = timeout;
 
        /*
@@ -836,15 +813,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
           relatively rare error condition, no care is taken to avoid
           unnecessary additional work such as memcpy's that could be avoided.
         */
-
-       /* 
-        * If SG_IO from block layer then set good_bytes to stop retries;
-        * else if errors, check them, and if necessary prepare for
-        * (partial) retries.
-        */
-       if (blk_pc_request(SCpnt->request))
-               good_bytes = this_count;
-       else if (driver_byte(result) != 0 &&
+       if (driver_byte(result) != 0 &&
                 sense_valid && !sense_deferred) {
                switch (sshdr.sense_key) {
                case MEDIUM_ERROR:
@@ -1635,10 +1604,10 @@ static int sd_remove(struct device *dev)
        del_gendisk(sdkp->disk);
        sd_shutdown(dev);
 
-       down(&sd_ref_sem);
+       mutex_lock(&sd_ref_mutex);
        dev_set_drvdata(dev, NULL);
        kref_put(&sdkp->kref, scsi_disk_release);
-       up(&sd_ref_sem);
+       mutex_unlock(&sd_ref_mutex);
 
        return 0;
 }
@@ -1647,7 +1616,7 @@ static int sd_remove(struct device *dev)
  *     scsi_disk_release - Called to free the scsi_disk structure
  *     @kref: pointer to embedded kref
  *
- *     sd_ref_sem must be held entering this routine.  Because it is
+ *     sd_ref_mutex must be held entering this routine.  Because it is
  *     called on last put, you should always use the scsi_disk_get()
  *     scsi_disk_put() helpers which manipulate the semaphore directly
  *     and never do a direct kref_put().
index a4d9be7c6874b471db06fe4a02503db46eb246bb..997f8e30509b89bf6e2f5af57a0bdffb689f9a87 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include <scsi/scsi.h>
@@ -90,7 +91,7 @@ static DEFINE_SPINLOCK(sr_index_lock);
 /* This semaphore is used to mediate the 0->1 reference get in the
  * face of object destruction (i.e. we can't allow a get on an
  * object after last put) */
-static DECLARE_MUTEX(sr_ref_sem);
+static DEFINE_MUTEX(sr_ref_mutex);
 
 static int sr_open(struct cdrom_device_info *, int);
 static void sr_release(struct cdrom_device_info *);
@@ -133,7 +134,7 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
 {
        struct scsi_cd *cd = NULL;
 
-       down(&sr_ref_sem);
+       mutex_lock(&sr_ref_mutex);
        if (disk->private_data == NULL)
                goto out;
        cd = scsi_cd(disk);
@@ -146,18 +147,18 @@ static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
        kref_put(&cd->kref, sr_kref_release);
        cd = NULL;
  out:
-       up(&sr_ref_sem);
+       mutex_unlock(&sr_ref_mutex);
        return cd;
 }
 
-static inline void scsi_cd_put(struct scsi_cd *cd)
+static void scsi_cd_put(struct scsi_cd *cd)
 {
        struct scsi_device *sdev = cd->device;
 
-       down(&sr_ref_sem);
+       mutex_lock(&sr_ref_mutex);
        kref_put(&cd->kref, sr_kref_release);
        scsi_device_put(sdev);
-       up(&sr_ref_sem);
+       mutex_unlock(&sr_ref_mutex);
 }
 
 /*
@@ -237,8 +238,6 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
                case ILLEGAL_REQUEST:
                        if (!(SCpnt->sense_buffer[0] & 0x90))
                                break;
-                       if (!blk_fs_request(SCpnt->request))
-                               break;
                        error_sector = (SCpnt->sense_buffer[3] << 24) |
                                (SCpnt->sense_buffer[4] << 16) |
                                (SCpnt->sense_buffer[5] << 8) |
@@ -316,23 +315,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
                return 0;
        }
 
-       /*
-        * these are already setup, just copy cdb basically
-        */
-       if (SCpnt->request->flags & REQ_BLOCK_PC) {
-               scsi_setup_blk_pc_cmnd(SCpnt);
-
-               if (SCpnt->timeout_per_command)
-                       timeout = SCpnt->timeout_per_command;
-
-               goto queue;
-       }
-
-       if (!(SCpnt->request->flags & REQ_CMD)) {
-               blk_dump_rq_flags(SCpnt->request, "sr unsup command");
-               return 0;
-       }
-
        /*
         * we do lazy blocksize switching (when reading XA sectors,
         * see CDROMREADMODE2 ioctl) 
@@ -421,8 +403,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
         */
        SCpnt->transfersize = cd->device->sector_size;
        SCpnt->underflow = this_count << 9;
-
-queue:
        SCpnt->allowed = MAX_RETRIES;
        SCpnt->timeout_per_command = timeout;
 
@@ -762,8 +742,9 @@ static void get_capabilities(struct scsi_cd *cd)
                /* failed, drive doesn't have capabilities mode page */
                cd->cdi.speed = 1;
                cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
-                                        CDC_DVD | CDC_DVD_RAM |
-                                        CDC_SELECT_DISC | CDC_SELECT_SPEED);
+                                CDC_DVD | CDC_DVD_RAM |
+                                CDC_SELECT_DISC | CDC_SELECT_SPEED |
+                                CDC_MRW | CDC_MRW_W | CDC_RAM);
                kfree(buffer);
                printk("%s: scsi-1 drive\n", cd->cdi.name);
                return;
@@ -845,7 +826,7 @@ static int sr_packet(struct cdrom_device_info *cdi,
  *     sr_kref_release - Called to free the scsi_cd structure
  *     @kref: pointer to embedded kref
  *
- *     sr_ref_sem must be held entering this routine.  Because it is
+ *     sr_ref_mutex must be held entering this routine.  Because it is
  *     called on last put, you should always use the scsi_cd_get()
  *     scsi_cd_put() helpers which manipulate the semaphore directly
  *     and never do a direct kref_put().
@@ -874,9 +855,9 @@ static int sr_remove(struct device *dev)
 
        del_gendisk(cd->disk);
 
-       down(&sr_ref_sem);
+       mutex_lock(&sr_ref_mutex);
        kref_put(&cd->kref, sr_kref_release);
-       up(&sr_ref_sem);
+       mutex_unlock(&sr_ref_mutex);
 
        return 0;
 }
index 6e45ac3c43c5e193b146ce793feb5ad51bf6e3d4..5d02ff4db6cc1e050d94ee83fa24899d9dc9050a 100644 (file)
@@ -31,6 +31,79 @@ static int xa_test = 0;
 
 module_param(xa_test, int, S_IRUGO | S_IWUSR);
 
+/* primitive to determine whether we need to have GFP_DMA set based on
+ * the status of the unchecked_isa_dma flag in the host structure */
+#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
+
+
+static int sr_read_tochdr(struct cdrom_device_info *cdi,
+               struct cdrom_tochdr *tochdr)
+{
+       struct scsi_cd *cd = cdi->handle;
+       struct packet_command cgc;
+       int result;
+       unsigned char *buffer;
+
+       buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+       if (!buffer)
+               return -ENOMEM;
+
+       memset(&cgc, 0, sizeof(struct packet_command));
+       cgc.timeout = IOCTL_TIMEOUT;
+       cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+       cgc.cmd[8] = 12;                /* LSB of length */
+       cgc.buffer = buffer;
+       cgc.buflen = 12;
+       cgc.quiet = 1;
+       cgc.data_direction = DMA_FROM_DEVICE;
+
+       result = sr_do_ioctl(cd, &cgc);
+
+       tochdr->cdth_trk0 = buffer[2];
+       tochdr->cdth_trk1 = buffer[3];
+
+       kfree(buffer);
+       return result;
+}
+
+static int sr_read_tocentry(struct cdrom_device_info *cdi,
+               struct cdrom_tocentry *tocentry)
+{
+       struct scsi_cd *cd = cdi->handle;
+       struct packet_command cgc;
+       int result;
+       unsigned char *buffer;
+
+       buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+       if (!buffer)
+               return -ENOMEM;
+
+       memset(&cgc, 0, sizeof(struct packet_command));
+       cgc.timeout = IOCTL_TIMEOUT;
+       cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+       cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
+       cgc.cmd[6] = tocentry->cdte_track;
+       cgc.cmd[8] = 12;                /* LSB of length */
+       cgc.buffer = buffer;
+       cgc.buflen = 12;
+       cgc.data_direction = DMA_FROM_DEVICE;
+
+       result = sr_do_ioctl(cd, &cgc);
+
+       tocentry->cdte_ctrl = buffer[5] & 0xf;
+       tocentry->cdte_adr = buffer[5] >> 4;
+       tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+       if (tocentry->cdte_format == CDROM_MSF) {
+               tocentry->cdte_addr.msf.minute = buffer[9];
+               tocentry->cdte_addr.msf.second = buffer[10];
+               tocentry->cdte_addr.msf.frame = buffer[11];
+       } else
+               tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+                       + buffer[10]) << 8) + buffer[11];
+
+       kfree(buffer);
+       return result;
+}
 
 #define IOCTL_RETRIES 3
 
@@ -45,7 +118,8 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti
        struct packet_command cgc;
        int ntracks, ret;
 
-       if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)))
+       ret = sr_read_tochdr(cdi, &tochdr);
+       if (ret)
                return ret;
 
        ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
@@ -60,9 +134,11 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti
        trk1_te.cdte_track = ti->cdti_trk1;
        trk1_te.cdte_format = CDROM_MSF;
        
-       if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk0_te)))
+       ret = sr_read_tocentry(cdi, &trk0_te);
+       if (ret)
                return ret;
-       if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te)))
+       ret = sr_read_tocentry(cdi, &trk1_te);
+       if (ret)
                return ret;
 
        memset(&cgc, 0, sizeof(struct packet_command));
@@ -78,6 +154,30 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti
        return sr_do_ioctl(cdi->handle, &cgc);
 }
 
+static int sr_play_trkind(struct cdrom_device_info *cdi,
+               struct cdrom_ti *ti)
+
+{
+       struct scsi_cd *cd = cdi->handle;
+       struct packet_command cgc;
+       int result;
+
+       memset(&cgc, 0, sizeof(struct packet_command));
+       cgc.timeout = IOCTL_TIMEOUT;
+       cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
+       cgc.cmd[4] = ti->cdti_trk0;
+       cgc.cmd[5] = ti->cdti_ind0;
+       cgc.cmd[7] = ti->cdti_trk1;
+       cgc.cmd[8] = ti->cdti_ind1;
+       cgc.data_direction = DMA_NONE;
+
+       result = sr_do_ioctl(cd, &cgc);
+       if (result == -EDRIVE_CANT_DO_THIS)
+               result = sr_fake_playtrkind(cdi, ti);
+
+       return result;
+}
+
 /* We do our own retries because we want to know what the specific
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
@@ -229,13 +329,14 @@ int sr_disk_status(struct cdrom_device_info *cdi)
        int i, rc, have_datatracks = 0;
 
        /* look for data tracks */
-       if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
+       rc = sr_read_tochdr(cdi, &toc_h);
+       if (rc)
                return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
 
        for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
                toc_e.cdte_track = i;
                toc_e.cdte_format = CDROM_LBA;
-               if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
+               if (sr_read_tocentry(cdi, &toc_e))
                        return CDS_NO_INFO;
                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
                        have_datatracks = 1;
@@ -262,10 +363,6 @@ int sr_get_last_session(struct cdrom_device_info *cdi,
        return 0;
 }
 
-/* primitive to determine whether we need to have GFP_DMA set based on
- * the status of the unchecked_isa_dma flag in the host structure */
-#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
-
 int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 {
        Scsi_CD *cd = cdi->handle;
@@ -329,93 +426,16 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 {
-       Scsi_CD *cd = cdi->handle;
-       struct packet_command cgc;
-       int result;
-       unsigned char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
-
-       if (!buffer)
-               return -ENOMEM;
-
-       memset(&cgc, 0, sizeof(struct packet_command));
-       cgc.timeout = IOCTL_TIMEOUT;
-
        switch (cmd) {
        case CDROMREADTOCHDR:
-               {
-                       struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
-
-                       cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-                       cgc.cmd[8] = 12;                /* LSB of length */
-                       cgc.buffer = buffer;
-                       cgc.buflen = 12;
-                       cgc.quiet = 1;
-                       cgc.data_direction = DMA_FROM_DEVICE;
-
-                       result = sr_do_ioctl(cd, &cgc);
-
-                       tochdr->cdth_trk0 = buffer[2];
-                       tochdr->cdth_trk1 = buffer[3];
-
-                       break;
-               }
-
+               return sr_read_tochdr(cdi, arg);
        case CDROMREADTOCENTRY:
-               {
-                       struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
-
-                       cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-                       cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
-                       cgc.cmd[6] = tocentry->cdte_track;
-                       cgc.cmd[8] = 12;                /* LSB of length */
-                       cgc.buffer = buffer;
-                       cgc.buflen = 12;
-                       cgc.data_direction = DMA_FROM_DEVICE;
-
-                       result = sr_do_ioctl(cd, &cgc);
-
-                       tocentry->cdte_ctrl = buffer[5] & 0xf;
-                       tocentry->cdte_adr = buffer[5] >> 4;
-                       tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
-                       if (tocentry->cdte_format == CDROM_MSF) {
-                               tocentry->cdte_addr.msf.minute = buffer[9];
-                               tocentry->cdte_addr.msf.second = buffer[10];
-                               tocentry->cdte_addr.msf.frame = buffer[11];
-                       } else
-                               tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
-                                       + buffer[10]) << 8) + buffer[11];
-
-                       break;
-               }
-
-       case CDROMPLAYTRKIND: {
-               struct cdrom_ti* ti = (struct cdrom_ti*)arg;
-
-               cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
-               cgc.cmd[4] = ti->cdti_trk0;
-               cgc.cmd[5] = ti->cdti_ind0;
-               cgc.cmd[7] = ti->cdti_trk1;
-               cgc.cmd[8] = ti->cdti_ind1;
-               cgc.data_direction = DMA_NONE;
-
-               result = sr_do_ioctl(cd, &cgc);
-               if (result == -EDRIVE_CANT_DO_THIS)
-                       result = sr_fake_playtrkind(cdi, ti);
-
-               break;
-       }
-
+               return sr_read_tocentry(cdi, arg);
+       case CDROMPLAYTRKIND:
+               return sr_play_trkind(cdi, arg);
        default:
-               result = -EINVAL;
+               return -EINVAL;
        }
-
-#if 0
-       if (result)
-               printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result);
-#endif
-
-       kfree(buffer);
-       return result;
 }
 
 /* -----------------------------------------------------------------------
index c4aade8f5345a34f949434df43f20fa847b139d1..13b1d3aac26521cf5b5e1518aaf9d062b5720dbb 100644 (file)
@@ -38,6 +38,7 @@ static const char *verstr = "20050830";
 #include <linux/devfs_fs_kernel.h>
 #include <linux/cdev.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <asm/dma.h>
@@ -193,7 +194,6 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
 
 static int st_probe(struct device *);
 static int st_remove(struct device *);
-static int st_init_command(struct scsi_cmnd *);
 
 static void do_create_driverfs_files(void);
 static void do_remove_driverfs_files(void);
@@ -206,7 +206,6 @@ static struct scsi_driver st_template = {
                .probe          = st_probe,
                .remove         = st_remove,
        },
-       .init_command           = st_init_command,
 };
 
 static int st_compression(struct scsi_tape *, int);
@@ -220,7 +219,7 @@ static void scsi_tape_release(struct kref *);
 
 #define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref)
 
-static DECLARE_MUTEX(st_ref_sem);
+static DEFINE_MUTEX(st_ref_mutex);
 
 \f
 #include "osst_detect.h"
@@ -237,7 +236,7 @@ static struct scsi_tape *scsi_tape_get(int dev)
 {
        struct scsi_tape *STp = NULL;
 
-       down(&st_ref_sem);
+       mutex_lock(&st_ref_mutex);
        write_lock(&st_dev_arr_lock);
 
        if (dev < st_dev_max && scsi_tapes != NULL)
@@ -259,7 +258,7 @@ out_put:
        STp = NULL;
 out:
        write_unlock(&st_dev_arr_lock);
-       up(&st_ref_sem);
+       mutex_unlock(&st_ref_mutex);
        return STp;
 }
 
@@ -267,10 +266,10 @@ static void scsi_tape_put(struct scsi_tape *STp)
 {
        struct scsi_device *sdev = STp->device;
 
-       down(&st_ref_sem);
+       mutex_lock(&st_ref_mutex);
        kref_put(&STp->kref, scsi_tape_release);
        scsi_device_put(sdev);
-       up(&st_ref_sem);
+       mutex_unlock(&st_ref_mutex);
 }
 
 struct st_reject_data {
@@ -4141,9 +4140,9 @@ static int st_remove(struct device *dev)
                                }
                        }
 
-                       down(&st_ref_sem);
+                       mutex_lock(&st_ref_mutex);
                        kref_put(&tpnt->kref, scsi_tape_release);
-                       up(&st_ref_sem);
+                       mutex_unlock(&st_ref_mutex);
                        return 0;
                }
        }
@@ -4156,7 +4155,7 @@ static int st_remove(struct device *dev)
  *      scsi_tape_release - Called to free the Scsi_Tape structure
  *      @kref: pointer to embedded kref
  *
- *      st_ref_sem must be held entering this routine.  Because it is
+ *      st_ref_mutex must be held entering this routine.  Because it is
  *      called on last put, you should always use the scsi_tape_get()
  *      scsi_tape_put() helpers which manipulate the semaphore directly
  *      and never do a direct kref_put().
@@ -4180,29 +4179,6 @@ static void scsi_tape_release(struct kref *kref)
        return;
 }
 
-static void st_intr(struct scsi_cmnd *SCpnt)
-{
-       /*
-        * The caller should be checking the request's errors
-        * value.
-        */
-       scsi_io_completion(SCpnt, SCpnt->bufflen, 0);
-}
-
-/*
- * st_init_command: only called via the scsi_cmd_ioctl (block SG_IO)
- * interface for REQ_BLOCK_PC commands.
- */
-static int st_init_command(struct scsi_cmnd *SCpnt)
-{
-       if (!(SCpnt->request->flags & REQ_BLOCK_PC))
-               return 0;
-
-       scsi_setup_blk_pc_cmnd(SCpnt);
-       SCpnt->done = st_intr;
-       return 1;
-}
-
 static int __init init_st(void)
 {
        validate_options();
index 4dd5c3f98167a143b2e29ea17b991540e618843d..8cbf0fc5a225ce0ba54a8a9eeb85ce65e15bfd12 100644 (file)
@@ -143,7 +143,6 @@ static int m68328_console_cbaud   = DEFAULT_CBAUD;
  * memory if large numbers of serial ports are open.
  */
 static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */
-DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct m68k_serial *info,
                                        char *name, const char *routine)
index fb610c3634a4b7f49f63a9bfebd0541dad7c19d9..d9ce8c54941651ef0fcd01c56a52b29f6d3c1a5a 100644 (file)
@@ -2454,6 +2454,7 @@ static struct platform_driver serial8250_isa_driver = {
        .resume         = serial8250_resume,
        .driver         = {
                .name   = "serial8250",
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -2594,21 +2595,30 @@ static int __init serial8250_init(void)
        if (ret)
                goto out;
 
-       serial8250_isa_devs = platform_device_register_simple("serial8250",
-                                        PLAT8250_DEV_LEGACY, NULL, 0);
-       if (IS_ERR(serial8250_isa_devs)) {
-               ret = PTR_ERR(serial8250_isa_devs);
-               goto unreg;
+       ret = platform_driver_register(&serial8250_isa_driver);
+       if (ret)
+               goto unreg_uart_drv;
+
+       serial8250_isa_devs = platform_device_alloc("serial8250",
+                                                   PLAT8250_DEV_LEGACY);
+       if (!serial8250_isa_devs) {
+               ret = -ENOMEM;
+               goto unreg_plat_drv;
        }
 
+       ret = platform_device_add(serial8250_isa_devs);
+       if (ret)
+               goto put_dev;
+
        serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
 
-       ret = platform_driver_register(&serial8250_isa_driver);
-       if (ret == 0)
-               goto out;
+       goto out;
 
-       platform_device_unregister(serial8250_isa_devs);
- unreg:
+ put_dev:
+       platform_device_put(serial8250_isa_devs);
+ unreg_plat_drv:
+       platform_driver_unregister(&serial8250_isa_driver);
+ unreg_uart_drv:
        uart_unregister_driver(&serial8250_reg);
  out:
        return ret;
index 843717275d497d7445f26f75f4aa1b0a68ebf40d..5e7199f7b59cda1e9a45da991c2ebc92e0ce4fe8 100644 (file)
@@ -190,7 +190,6 @@ config SERIAL_8250_BOCA
          To compile this driver as a module, choose M here: the module
          will be called 8250_boca.
 
-
 config SERIAL_8250_HUB6
        tristate "Support Hub6 cards"
        depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
@@ -848,7 +847,7 @@ config SERIAL_M32R_SIO_CONSOLE
 
 config SERIAL_M32R_PLDSIO
        bool "M32R SIO I/F on a PLD"
-       depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PALT_USRV || PLAT_M32700UT)
+       depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT)
        default n
        help
          Say Y here if you want to use the M32R serial controller
@@ -917,4 +916,12 @@ config SERIAL_SGI_IOC4
                and wish to use the serial ports on this card, say Y.
                Otherwise, say N.
 
+config SERIAL_SGI_IOC3
+       tristate "SGI Altix IOC3 serial support"
+       depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3
+       select SERIAL_CORE
+       help
+         If you have an SGI Altix with an IOC3 serial card,
+         say Y or M.  Otherwise, say N.
+
 endmenu
index 24a583e482bbf149a6b1aa26acca9781bab42cbc..eaf8e01db1982b24a9a6787071e915767cf2d0a0 100644 (file)
@@ -56,4 +56,5 @@ obj-$(CONFIG_SERIAL_JSM) += jsm/
 obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
 obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
index 5c098be9346b35de2b8ed58b0b6648df8c7c160a..587cc6a9511461732d355f7c32b4dc33117d52b3 100644 (file)
@@ -499,7 +499,7 @@ imx_set_termios(struct uart_port *port, struct termios *termios,
                ucr2 |= UCR2_STPB;
        if (termios->c_cflag & PARENB) {
                ucr2 |= UCR2_PREN;
-               if (!(termios->c_cflag & PARODD))
+               if (termios->c_cflag & PARODD)
                        ucr2 |= UCR2_PROE;
        }
 
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
new file mode 100644 (file)
index 0000000..8097cd9
--- /dev/null
@@ -0,0 +1,2197 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+/*
+ * This file contains a module version of the ioc3 serial driver. This
+ * includes all the support functions needed (support functions, etc.)
+ * and the serial driver itself.
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/circ_buf.h>
+#include <linux/serial_reg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/serial_core.h>
+#include <linux/ioc3.h>
+
+/*
+ * Interesting things about the ioc3
+ */
+
+#define LOGICAL_PORTS          2       /* rs232(0) and rs422(1) */
+#define PORTS_PER_CARD         2
+#define LOGICAL_PORTS_PER_CARD (PORTS_PER_CARD * LOGICAL_PORTS)
+#define MAX_CARDS              8
+#define MAX_LOGICAL_PORTS      (LOGICAL_PORTS_PER_CARD * MAX_CARDS)
+
+/* determine given the sio_ir what port it applies to */
+#define GET_PORT_FROM_SIO_IR(_x)       (_x & SIO_IR_SA) ? 0 : 1
+
+
+/*
+ * we have 2 logical ports (rs232, rs422) for each physical port
+ * evens are rs232, odds are rs422
+ */
+#define GET_PHYSICAL_PORT(_x)  ((_x) >> 1)
+#define GET_LOGICAL_PORT(_x)   ((_x) & 1)
+#define IS_PHYSICAL_PORT(_x)   !((_x) & 1)
+#define IS_RS232(_x)           !((_x) & 1)
+
+static unsigned int Num_of_ioc3_cards;
+static unsigned int Submodule_slot;
+
+/* defining this will get you LOTS of great debug info */
+//#define DEBUG_INTERRUPTS
+#define DPRINT_CONFIG(_x...)   ;
+//#define DPRINT_CONFIG(_x...)  printk _x
+#define NOT_PROGRESS() ;
+//#define NOT_PROGRESS()       printk("%s : fails %d\n", __FUNCTION__, __LINE__)
+
+/* number of characters we want to transmit to the lower level at a time */
+#define MAX_CHARS              256
+#define FIFO_SIZE              (MAX_CHARS-1)   /* it's a uchar */
+
+/* Device name we're using */
+#define DEVICE_NAME            "ttySIOC"
+#define DEVICE_MAJOR           204
+#define DEVICE_MINOR           116
+
+/* flags for next_char_state */
+#define NCS_BREAK              0x1
+#define NCS_PARITY             0x2
+#define NCS_FRAMING            0x4
+#define NCS_OVERRUN            0x8
+
+/* cause we need SOME parameters ... */
+#define MIN_BAUD_SUPPORTED     1200
+#define MAX_BAUD_SUPPORTED     115200
+
+/* protocol types supported */
+#define PROTO_RS232            0
+#define PROTO_RS422            1
+
+/* Notification types */
+#define N_DATA_READY           0x01
+#define N_OUTPUT_LOWAT         0x02
+#define N_BREAK                        0x04
+#define N_PARITY_ERROR         0x08
+#define N_FRAMING_ERROR                0x10
+#define N_OVERRUN_ERROR                0x20
+#define N_DDCD                 0x40
+#define N_DCTS                 0x80
+
+#define N_ALL_INPUT            (N_DATA_READY | N_BREAK                    \
+                                       | N_PARITY_ERROR | N_FRAMING_ERROR \
+                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define N_ALL_OUTPUT           N_OUTPUT_LOWAT
+
+#define N_ALL_ERRORS           (N_PARITY_ERROR | N_FRAMING_ERROR \
+                                               | N_OVERRUN_ERROR)
+
+#define N_ALL                  (N_DATA_READY | N_OUTPUT_LOWAT | N_BREAK    \
+                                       | N_PARITY_ERROR | N_FRAMING_ERROR  \
+                                       | N_OVERRUN_ERROR | N_DDCD | N_DCTS)
+
+#define SER_CLK_SPEED(prediv)  ((22000000 << 1) / prediv)
+#define SER_DIVISOR(x, clk)    (((clk) + (x) * 8) / ((x) * 16))
+#define DIVISOR_TO_BAUD(div, clk) ((clk) / 16 / (div))
+
+/* Some masks */
+#define LCR_MASK_BITS_CHAR     (UART_LCR_WLEN5 | UART_LCR_WLEN6 \
+                                       | UART_LCR_WLEN7 | UART_LCR_WLEN8)
+#define LCR_MASK_STOP_BITS     (UART_LCR_STOP)
+
+#define PENDING(_a, _p)                (readl(&(_p)->vma->sio_ir) & (_a)->ic_enable)
+
+#define RING_BUF_SIZE          4096
+#define BUF_SIZE_BIT           SBBR_L_SIZE
+#define PROD_CONS_MASK         PROD_CONS_PTR_4K
+
+#define TOTAL_RING_BUF_SIZE    (RING_BUF_SIZE * 4)
+
+/* driver specific - one per card */
+struct ioc3_card {
+       struct {
+               /* uart ports are allocated here */
+               struct uart_port icp_uart_port[LOGICAL_PORTS];
+               /* the ioc3_port used for this port */
+               struct ioc3_port *icp_port;
+       } ic_port[PORTS_PER_CARD];
+       /* currently enabled interrupts */
+       uint32_t ic_enable;
+};
+
+/* Local port info for each IOC3 serial port */
+struct ioc3_port {
+       /* handy reference material */
+       struct uart_port *ip_port;
+       struct ioc3_card *ip_card;
+       struct ioc3_driver_data *ip_idd;
+       struct ioc3_submodule *ip_is;
+
+       /* pci mem addresses for this port */
+       struct ioc3_serialregs __iomem *ip_serial_regs;
+       struct ioc3_uartregs __iomem *ip_uart_regs;
+
+       /* Ring buffer page for this port */
+       dma_addr_t ip_dma_ringbuf;
+       /* vaddr of ring buffer */
+       struct ring_buffer *ip_cpu_ringbuf;
+
+       /* Rings for this port */
+       struct ring *ip_inring;
+       struct ring *ip_outring;
+
+       /* Hook to port specific values */
+       struct port_hooks *ip_hooks;
+
+       spinlock_t ip_lock;
+
+       /* Various rx/tx parameters */
+       int ip_baud;
+       int ip_tx_lowat;
+       int ip_rx_timeout;
+
+       /* Copy of notification bits */
+       int ip_notify;
+
+       /* Shadow copies of various registers so we don't need to PIO
+        * read them constantly
+        */
+       uint32_t ip_sscr;
+       uint32_t ip_tx_prod;
+       uint32_t ip_rx_cons;
+       unsigned char ip_flags;
+};
+
+/* tx low water mark.  We need to notify the driver whenever tx is getting
+ * close to empty so it can refill the tx buffer and keep things going.
+ * Let's assume that if we interrupt 1 ms before the tx goes idle, we'll
+ * have no trouble getting in more chars in time (I certainly hope so).
+ */
+#define TX_LOWAT_LATENCY      1000
+#define TX_LOWAT_HZ          (1000000 / TX_LOWAT_LATENCY)
+#define TX_LOWAT_CHARS(baud) (baud / 10 / TX_LOWAT_HZ)
+
+/* Flags per port */
+#define INPUT_HIGH             0x01
+       /* used to signify that we have turned off the rx_high
+        * temporarily - we need to drain the fifo and don't
+        * want to get blasted with interrupts.
+        */
+#define DCD_ON                 0x02
+       /* DCD state is on */
+#define LOWAT_WRITTEN          0x04
+#define READ_ABORTED           0x08
+       /* the read was aborted - used to avaoid infinate looping
+        * in the interrupt handler
+        */
+#define INPUT_ENABLE           0x10
+
+/* Since each port has different register offsets and bitmasks
+ * for everything, we'll store those that we need in tables so we
+ * don't have to be constantly checking the port we are dealing with.
+ */
+struct port_hooks {
+       uint32_t intr_delta_dcd;
+       uint32_t intr_delta_cts;
+       uint32_t intr_tx_mt;
+       uint32_t intr_rx_timer;
+       uint32_t intr_rx_high;
+       uint32_t intr_tx_explicit;
+       uint32_t intr_clear;
+       uint32_t intr_all;
+       char rs422_select_pin;
+};
+
+static struct port_hooks hooks_array[PORTS_PER_CARD] = {
+       /* values for port A */
+       {
+       .intr_delta_dcd = SIO_IR_SA_DELTA_DCD,
+       .intr_delta_cts = SIO_IR_SA_DELTA_CTS,
+       .intr_tx_mt = SIO_IR_SA_TX_MT,
+       .intr_rx_timer = SIO_IR_SA_RX_TIMER,
+       .intr_rx_high = SIO_IR_SA_RX_HIGH,
+       .intr_tx_explicit = SIO_IR_SA_TX_EXPLICIT,
+       .intr_clear = (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL
+                               | SIO_IR_SA_RX_HIGH
+                               | SIO_IR_SA_RX_TIMER
+                               | SIO_IR_SA_DELTA_DCD
+                               | SIO_IR_SA_DELTA_CTS
+                               | SIO_IR_SA_INT
+                               | SIO_IR_SA_TX_EXPLICIT
+                               | SIO_IR_SA_MEMERR),
+       .intr_all =  SIO_IR_SA,
+       .rs422_select_pin = GPPR_UARTA_MODESEL_PIN,
+        },
+
+       /* values for port B */
+       {
+       .intr_delta_dcd = SIO_IR_SB_DELTA_DCD,
+       .intr_delta_cts = SIO_IR_SB_DELTA_CTS,
+       .intr_tx_mt = SIO_IR_SB_TX_MT,
+       .intr_rx_timer = SIO_IR_SB_RX_TIMER,
+       .intr_rx_high = SIO_IR_SB_RX_HIGH,
+       .intr_tx_explicit = SIO_IR_SB_TX_EXPLICIT,
+       .intr_clear = (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL
+                               | SIO_IR_SB_RX_HIGH
+                               | SIO_IR_SB_RX_TIMER
+                               | SIO_IR_SB_DELTA_DCD
+                               | SIO_IR_SB_DELTA_CTS
+                               | SIO_IR_SB_INT
+                               | SIO_IR_SB_TX_EXPLICIT
+                               | SIO_IR_SB_MEMERR),
+       .intr_all = SIO_IR_SB,
+       .rs422_select_pin = GPPR_UARTB_MODESEL_PIN,
+        }
+};
+
+struct ring_entry {
+       union {
+               struct {
+                       uint32_t alldata;
+                       uint32_t allsc;
+               } all;
+               struct {
+                       char data[4];   /* data bytes */
+                       char sc[4];     /* status/control */
+               } s;
+       } u;
+};
+
+/* Test the valid bits in any of the 4 sc chars using "allsc" member */
+#define RING_ANY_VALID \
+       ((uint32_t)(RXSB_MODEM_VALID | RXSB_DATA_VALID) * 0x01010101)
+
+#define ring_sc                u.s.sc
+#define ring_data      u.s.data
+#define ring_allsc     u.all.allsc
+
+/* Number of entries per ring buffer. */
+#define ENTRIES_PER_RING (RING_BUF_SIZE / (int) sizeof(struct ring_entry))
+
+/* An individual ring */
+struct ring {
+       struct ring_entry entries[ENTRIES_PER_RING];
+};
+
+/* The whole enchilada */
+struct ring_buffer {
+       struct ring TX_A;
+       struct ring RX_A;
+       struct ring TX_B;
+       struct ring RX_B;
+};
+
+/* Get a ring from a port struct */
+#define RING(_p, _wh)  &(((struct ring_buffer *)((_p)->ip_cpu_ringbuf))->_wh)
+
+/* for Infinite loop detection  */
+#define MAXITER                10000000
+
+
+/**
+ * set_baud - Baud rate setting code
+ * @port: port to set
+ * @baud: baud rate to use
+ */
+static int set_baud(struct ioc3_port *port, int baud)
+{
+       int divisor;
+       int actual_baud;
+       int diff;
+       int lcr, prediv;
+       struct ioc3_uartregs __iomem *uart;
+
+       for (prediv = 6; prediv < 64; prediv++) {
+               divisor = SER_DIVISOR(baud, SER_CLK_SPEED(prediv));
+               if (!divisor)
+                       continue;       /* invalid divisor */
+               actual_baud = DIVISOR_TO_BAUD(divisor, SER_CLK_SPEED(prediv));
+
+               diff = actual_baud - baud;
+               if (diff < 0)
+                       diff = -diff;
+
+               /* if we're within 1% we've found a match */
+               if (diff * 100 <= actual_baud)
+                       break;
+       }
+
+       /* if the above loop completed, we didn't match
+        * the baud rate.  give up.
+        */
+       if (prediv == 64) {
+               NOT_PROGRESS();
+               return 1;
+       }
+
+       uart = port->ip_uart_regs;
+       lcr = readb(&uart->iu_lcr);
+
+       writeb(lcr | UART_LCR_DLAB, &uart->iu_lcr);
+       writeb((unsigned char)divisor, &uart->iu_dll);
+       writeb((unsigned char)(divisor >> 8), &uart->iu_dlm);
+       writeb((unsigned char)prediv, &uart->iu_scr);
+       writeb((unsigned char)lcr, &uart->iu_lcr);
+
+       return 0;
+}
+
+/**
+ * get_ioc3_port - given a uart port, return the control structure
+ * @the_port: uart port to find
+ */
+static struct ioc3_port *get_ioc3_port(struct uart_port *the_port)
+{
+       struct ioc3_driver_data *idd = dev_get_drvdata(the_port->dev);
+       struct ioc3_card *card_ptr = idd->data[Submodule_slot];
+       int ii, jj;
+
+       if (!card_ptr) {
+               NOT_PROGRESS();
+               return NULL;
+       }
+       for (ii = 0; ii < PORTS_PER_CARD; ii++) {
+               for (jj = 0; jj < LOGICAL_PORTS; jj++) {
+                       if (the_port == &card_ptr->ic_port[ii].icp_uart_port[jj])
+                               return card_ptr->ic_port[ii].icp_port;
+               }
+       }
+       NOT_PROGRESS();
+       return NULL;
+}
+
+/**
+ * port_init - Initialize the sio and ioc3 hardware for a given port
+ *                     called per port from attach...
+ * @port: port to initialize
+ */
+static int inline port_init(struct ioc3_port *port)
+{
+       uint32_t sio_cr;
+       struct port_hooks *hooks = port->ip_hooks;
+       struct ioc3_uartregs __iomem *uart;
+       int reset_loop_counter = 0xfffff;
+       struct ioc3_driver_data *idd = port->ip_idd;
+
+       /* Idle the IOC3 serial interface */
+       writel(SSCR_RESET, &port->ip_serial_regs->sscr);
+
+       /* Wait until any pending bus activity for this port has ceased */
+       do {
+               sio_cr = readl(&idd->vma->sio_cr);
+               if (reset_loop_counter-- <= 0) {
+                       printk(KERN_WARNING
+                              "IOC3 unable to come out of reset"
+                               " scr 0x%x\n", sio_cr);
+                       return -1;
+               }
+       } while (!(sio_cr & SIO_CR_ARB_DIAG_IDLE) &&
+              (((sio_cr &= SIO_CR_ARB_DIAG) == SIO_CR_ARB_DIAG_TXA)
+               || sio_cr == SIO_CR_ARB_DIAG_TXB
+               || sio_cr == SIO_CR_ARB_DIAG_RXA
+               || sio_cr == SIO_CR_ARB_DIAG_RXB));
+
+       /* Finish reset sequence */
+       writel(0, &port->ip_serial_regs->sscr);
+
+       /* Once RESET is done, reload cached tx_prod and rx_cons values
+        * and set rings to empty by making prod == cons
+        */
+       port->ip_tx_prod = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       writel(port->ip_tx_prod, &port->ip_serial_regs->stpir);
+       port->ip_rx_cons = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       /* Disable interrupts for this 16550 */
+       uart = port->ip_uart_regs;
+       writeb(0, &uart->iu_lcr);
+       writeb(0, &uart->iu_ier);
+
+       /* Set the default baud */
+       set_baud(port, port->ip_baud);
+
+       /* Set line control to 8 bits no parity */
+       writeb(UART_LCR_WLEN8 | 0, &uart->iu_lcr);
+       /* UART_LCR_STOP == 1 stop */
+
+       /* Enable the FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO, &uart->iu_fcr);
+       /* then reset 16550 FIFOs */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
+              &uart->iu_fcr);
+
+       /* Clear modem control register */
+       writeb(0, &uart->iu_mcr);
+
+       /* Clear deltas in modem status register */
+       writel(0, &port->ip_serial_regs->shadow);
+
+       /* Only do this once per port pair */
+       if (port->ip_hooks == &hooks_array[0]) {
+               unsigned long ring_pci_addr;
+               uint32_t __iomem *sbbr_l, *sbbr_h;
+
+               sbbr_l = &idd->vma->sbbr_l;
+               sbbr_h = &idd->vma->sbbr_h;
+               ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
+               DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
+                              __FUNCTION__, (void *)ring_pci_addr));
+
+               writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
+               writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
+       }
+
+       /* Set the receive timeout value to 10 msec */
+       writel(SRTR_HZ / 100, &port->ip_serial_regs->srtr);
+
+       /* Set rx threshold, enable DMA */
+       /* Set high water mark at 3/4 of full ring */
+       port->ip_sscr = (ENTRIES_PER_RING * 3 / 4);
+
+       /* uart experiences pauses at high baud rate reducing actual
+        * throughput by 10% or so unless we enable high speed polling
+        * XXX when this hardware bug is resolved we should revert to
+        * normal polling speed
+        */
+       port->ip_sscr |= SSCR_HIGH_SPD;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Disable and clear all serial related interrupt bits */
+       port->ip_card->ic_enable &= ~hooks->intr_clear;
+       ioc3_disable(port->ip_is, idd, hooks->intr_clear);
+       ioc3_ack(port->ip_is, idd, hooks->intr_clear);
+       return 0;
+}
+
+/**
+ * enable_intrs - enable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static void enable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+       if ((port->ip_card->ic_enable & mask) != mask) {
+               port->ip_card->ic_enable |= mask;
+               ioc3_enable(port->ip_is, port->ip_idd, mask);
+       }
+}
+
+/**
+ * local_open - local open a port
+ * @port: port to open
+ */
+static inline int local_open(struct ioc3_port *port)
+{
+       int spiniter = 0;
+
+       port->ip_flags = INPUT_ENABLE;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER) {
+                               NOT_PROGRESS();
+                               return -1;
+                       }
+               }
+       }
+
+       /* Reset the input fifo.  If the uart received chars while the port
+        * was closed and DMA is not enabled, the uart may have a bunch of
+        * chars hanging around in its rx fifo which will not be discarded
+        * by rclr in the upper layer. We must get rid of them here.
+        */
+       writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR,
+              &port->ip_uart_regs->iu_fcr);
+
+       writeb(UART_LCR_WLEN8, &port->ip_uart_regs->iu_lcr);
+       /* UART_LCR_STOP == 1 stop */
+
+       /* Re-enable DMA, set default threshold to intr whenever there is
+        * data available.
+        */
+       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+       port->ip_sscr |= 1;     /* default threshold */
+
+       /* Plug in the new sscr.  This implicitly clears the DMA_PAUSE
+        * flag if it was set above
+        */
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       port->ip_tx_lowat = 1;
+       return 0;
+}
+
+/**
+ * set_rx_timeout - Set rx timeout and threshold values.
+ * @port: port to use
+ * @timeout: timeout value in ticks
+ */
+static inline int set_rx_timeout(struct ioc3_port *port, int timeout)
+{
+       int threshold;
+
+       port->ip_rx_timeout = timeout;
+
+       /* Timeout is in ticks.  Let's figure out how many chars we
+        * can receive at the current baud rate in that interval
+        * and set the rx threshold to that amount.  There are 4 chars
+        * per ring entry, so we'll divide the number of chars that will
+        * arrive in timeout by 4.
+        * So .... timeout * baud / 10 / HZ / 4, with HZ = 100.
+        */
+       threshold = timeout * port->ip_baud / 4000;
+       if (threshold == 0)
+               threshold = 1;  /* otherwise we'll intr all the time! */
+
+       if ((unsigned)threshold > (unsigned)SSCR_RX_THRESHOLD)
+               return 1;
+
+       port->ip_sscr &= ~SSCR_RX_THRESHOLD;
+       port->ip_sscr |= threshold;
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Now set the rx timeout to the given value
+        * again timeout * SRTR_HZ / HZ
+        */
+       timeout = timeout * SRTR_HZ / 100;
+       if (timeout > SRTR_CNT)
+               timeout = SRTR_CNT;
+       writel(timeout, &port->ip_serial_regs->srtr);
+       return 0;
+}
+
+/**
+ * config_port - config the hardware
+ * @port: port to config
+ * @baud: baud rate for the port
+ * @byte_size: data size
+ * @stop_bits: number of stop bits
+ * @parenb: parity enable ?
+ * @parodd: odd parity ?
+ */
+static inline int
+config_port(struct ioc3_port *port,
+           int baud, int byte_size, int stop_bits, int parenb, int parodd)
+{
+       char lcr, sizebits;
+       int spiniter = 0;
+
+       DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
+                       "parodd %d\n",
+                      __FUNCTION__, ((struct uart_port *)port->ip_port)->line,
+                       baud, byte_size, stop_bits, parenb, parodd));
+
+       if (set_baud(port, baud))
+               return 1;
+
+       switch (byte_size) {
+       case 5:
+               sizebits = UART_LCR_WLEN5;
+               break;
+       case 6:
+               sizebits = UART_LCR_WLEN6;
+               break;
+       case 7:
+               sizebits = UART_LCR_WLEN7;
+               break;
+       case 8:
+               sizebits = UART_LCR_WLEN8;
+               break;
+       default:
+               return 1;
+       }
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+
+       /* Clear relevant fields in lcr */
+       lcr = readb(&port->ip_uart_regs->iu_lcr);
+       lcr &= ~(LCR_MASK_BITS_CHAR | UART_LCR_EPAR |
+                UART_LCR_PARITY | LCR_MASK_STOP_BITS);
+
+       /* Set byte size in lcr */
+       lcr |= sizebits;
+
+       /* Set parity */
+       if (parenb) {
+               lcr |= UART_LCR_PARITY;
+               if (!parodd)
+                       lcr |= UART_LCR_EPAR;
+       }
+
+       /* Set stop bits */
+       if (stop_bits)
+               lcr |= UART_LCR_STOP /* 2 stop bits */ ;
+
+       writeb(lcr, &port->ip_uart_regs->iu_lcr);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       port->ip_baud = baud;
+
+       /* When we get within this number of ring entries of filling the
+        * entire ring on tx, place an EXPLICIT intr to generate a lowat
+        * notification when output has drained.
+        */
+       port->ip_tx_lowat = (TX_LOWAT_CHARS(baud) + 3) / 4;
+       if (port->ip_tx_lowat == 0)
+               port->ip_tx_lowat = 1;
+
+       set_rx_timeout(port, 2);
+       return 0;
+}
+
+/**
+ * do_write - Write bytes to the port.  Returns the number of bytes
+ *                     actually written. Called from transmit_chars
+ * @port: port to use
+ * @buf: the stuff to write
+ * @len: how many bytes in 'buf'
+ */
+static inline int do_write(struct ioc3_port *port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total = 0;
+       struct ring *outring;
+       struct ring_entry *entry;
+       struct port_hooks *hooks = port->ip_hooks;
+
+       BUG_ON(!(len >= 0));
+
+       prod_ptr = port->ip_tx_prod;
+       cons_ptr = readl(&port->ip_serial_regs->stcir) & PROD_CONS_MASK;
+       outring = port->ip_outring;
+
+       /* Maintain a 1-entry red-zone.  The ring buffer is full when
+        * (cons - prod) % ring_size is 1.  Rather than do this subtraction
+        * in the body of the loop, I'll do it now.
+        */
+       cons_ptr = (cons_ptr - (int)sizeof(struct ring_entry)) & PROD_CONS_MASK;
+
+       /* Stuff the bytes into the output */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               int xx;
+
+               /* Get 4 bytes (one ring entry) at a time */
+               entry = (struct ring_entry *)((caddr_t) outring + prod_ptr);
+
+               /* Invalidate all entries */
+               entry->ring_allsc = 0;
+
+               /* Copy in some bytes */
+               for (xx = 0; (xx < 4) && (len > 0); xx++) {
+                       entry->ring_data[xx] = *buf++;
+                       entry->ring_sc[xx] = TXCB_VALID;
+                       len--;
+                       total++;
+               }
+
+               /* If we are within some small threshold of filling up the
+                * entire ring buffer, we must place an EXPLICIT intr here
+                * to generate a lowat interrupt in case we subsequently
+                * really do fill up the ring and the caller goes to sleep.
+                * No need to place more than one though.
+                */
+               if (!(port->ip_flags & LOWAT_WRITTEN) &&
+                   ((cons_ptr - prod_ptr) & PROD_CONS_MASK)
+                   <= port->ip_tx_lowat * (int)sizeof(struct ring_entry)) {
+                       port->ip_flags |= LOWAT_WRITTEN;
+                       entry->ring_sc[0] |= TXCB_INT_WHEN_DONE;
+               }
+
+               /* Go on to next entry */
+               prod_ptr += sizeof(struct ring_entry);
+               prod_ptr &= PROD_CONS_MASK;
+       }
+
+       /* If we sent something, start DMA if necessary */
+       if (total > 0 && !(port->ip_sscr & SSCR_DMA_EN)) {
+               port->ip_sscr |= SSCR_DMA_EN;
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+
+       /* Store the new producer pointer.  If tx is disabled, we stuff the
+        * data into the ring buffer, but we don't actually start tx.
+        */
+       if (!uart_tx_stopped(port->ip_port)) {
+               writel(prod_ptr, &port->ip_serial_regs->stpir);
+
+               /* If we are now transmitting, enable tx_mt interrupt so we
+                * can disable DMA if necessary when the tx finishes.
+                */
+               if (total > 0)
+                       enable_intrs(port, hooks->intr_tx_mt);
+       }
+       port->ip_tx_prod = prod_ptr;
+
+       return total;
+}
+
+/**
+ * disable_intrs - disable interrupts
+ * @port: port to enable
+ * @mask: mask to use
+ */
+static inline void disable_intrs(struct ioc3_port *port, uint32_t mask)
+{
+       if (port->ip_card->ic_enable & mask) {
+               ioc3_disable(port->ip_is, port->ip_idd, mask);
+               port->ip_card->ic_enable &= ~mask;
+       }
+}
+
+/**
+ * set_notification - Modify event notification
+ * @port: port to use
+ * @mask: events mask
+ * @set_on: set ?
+ */
+static int set_notification(struct ioc3_port *port, int mask, int set_on)
+{
+       struct port_hooks *hooks = port->ip_hooks;
+       uint32_t intrbits, sscrbits;
+
+       BUG_ON(!mask);
+
+       intrbits = sscrbits = 0;
+
+       if (mask & N_DATA_READY)
+               intrbits |= (hooks->intr_rx_timer | hooks->intr_rx_high);
+       if (mask & N_OUTPUT_LOWAT)
+               intrbits |= hooks->intr_tx_explicit;
+       if (mask & N_DDCD) {
+               intrbits |= hooks->intr_delta_dcd;
+               sscrbits |= SSCR_RX_RING_DCD;
+       }
+       if (mask & N_DCTS)
+               intrbits |= hooks->intr_delta_cts;
+
+       if (set_on) {
+               enable_intrs(port, intrbits);
+               port->ip_notify |= mask;
+               port->ip_sscr |= sscrbits;
+       } else {
+               disable_intrs(port, intrbits);
+               port->ip_notify &= ~mask;
+               port->ip_sscr &= ~sscrbits;
+       }
+
+       /* We require DMA if either DATA_READY or DDCD notification is
+        * currently requested. If neither of these is requested and
+        * there is currently no tx in progress, DMA may be disabled.
+        */
+       if (port->ip_notify & (N_DATA_READY | N_DDCD))
+               port->ip_sscr |= SSCR_DMA_EN;
+       else if (!(port->ip_card->ic_enable & hooks->intr_tx_mt))
+               port->ip_sscr &= ~SSCR_DMA_EN;
+
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       return 0;
+}
+
+/**
+ * set_mcr - set the master control reg
+ * @the_port: port to use
+ * @mask1: mcr mask
+ * @mask2: shadow mask
+ */
+static inline int set_mcr(struct uart_port *the_port,
+                         int mask1, int mask2)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       uint32_t shadow;
+       int spiniter = 0;
+       char mcr;
+
+       if (!port)
+               return -1;
+
+       /* Pause the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr | SSCR_DMA_PAUSE,
+                      &port->ip_serial_regs->sscr);
+               while ((readl(&port->ip_serial_regs->sscr)
+                       & SSCR_PAUSE_STATE) == 0) {
+                       spiniter++;
+                       if (spiniter > MAXITER)
+                               return -1;
+               }
+       }
+       shadow = readl(&port->ip_serial_regs->shadow);
+       mcr = (shadow & 0xff000000) >> 24;
+
+       /* Set new value */
+       mcr |= mask1;
+       shadow |= mask2;
+       writeb(mcr, &port->ip_uart_regs->iu_mcr);
+       writel(shadow, &port->ip_serial_regs->shadow);
+
+       /* Re-enable the DMA interface if necessary */
+       if (port->ip_sscr & SSCR_DMA_EN) {
+               writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+       }
+       return 0;
+}
+
+/**
+ * ioc3_set_proto - set the protocol for the port
+ * @port: port to use
+ * @proto: protocol to use
+ */
+static int ioc3_set_proto(struct ioc3_port *port, int proto)
+{
+       struct port_hooks *hooks = port->ip_hooks;
+
+       switch (proto) {
+       default:
+       case PROTO_RS232:
+               /* Clear the appropriate GIO pin */
+               DPRINT_CONFIG(("%s: rs232\n", __FUNCTION__));
+               writel(0, (&port->ip_idd->vma->gppr[0]
+                                       + hooks->rs422_select_pin));
+               break;
+
+       case PROTO_RS422:
+               /* Set the appropriate GIO pin */
+               DPRINT_CONFIG(("%s: rs422\n", __FUNCTION__));
+               writel(1, (&port->ip_idd->vma->gppr[0]
+                                       + hooks->rs422_select_pin));
+               break;
+       }
+       return 0;
+}
+
+/**
+ * transmit_chars - upper level write, called with the_port->lock
+ * @the_port: port to write
+ */
+static void transmit_chars(struct uart_port *the_port)
+{
+       int xmit_count, tail, head;
+       int result;
+       char *start;
+       struct tty_struct *tty;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       struct uart_info *info;
+
+       if (!the_port)
+               return;
+       if (!port)
+               return;
+
+       info = the_port->info;
+       tty = info->tty;
+
+       if (uart_circ_empty(&info->xmit) || uart_tx_stopped(the_port)) {
+               /* Nothing to do or hw stopped */
+               set_notification(port, N_ALL_OUTPUT, 0);
+               return;
+       }
+
+       head = info->xmit.head;
+       tail = info->xmit.tail;
+       start = (char *)&info->xmit.buf[tail];
+
+       /* write out all the data or until the end of the buffer */
+       xmit_count = (head < tail) ? (UART_XMIT_SIZE - tail) : (head - tail);
+       if (xmit_count > 0) {
+               result = do_write(port, start, xmit_count);
+               if (result > 0) {
+                       /* booking */
+                       xmit_count -= result;
+                       the_port->icount.tx += result;
+                       /* advance the pointers */
+                       tail += result;
+                       tail &= UART_XMIT_SIZE - 1;
+                       info->xmit.tail = tail;
+                       start = (char *)&info->xmit.buf[tail];
+               }
+       }
+       if (uart_circ_chars_pending(&info->xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(the_port);
+
+       if (uart_circ_empty(&info->xmit)) {
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+       } else {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+       }
+}
+
+/**
+ * ioc3_change_speed - change the speed of the port
+ * @the_port: port to change
+ * @new_termios: new termios settings
+ * @old_termios: old termios settings
+ */
+static void
+ioc3_change_speed(struct uart_port *the_port,
+                 struct termios *new_termios, struct termios *old_termios)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       unsigned int cflag;
+       int baud;
+       int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8;
+       struct uart_info *info = the_port->info;
+
+       cflag = new_termios->c_cflag;
+
+       switch (cflag & CSIZE) {
+       case CS5:
+               new_data = 5;
+               break;
+       case CS6:
+               new_data = 6;
+               break;
+       case CS7:
+               new_data = 7;
+               break;
+       case CS8:
+               new_data = 8;
+               break;
+       default:
+               /* cuz we always need a default ... */
+               new_data = 5;
+               break;
+       }
+       if (cflag & CSTOPB) {
+               new_stop = 1;
+       }
+       if (cflag & PARENB) {
+               new_parity_enable = 1;
+               if (cflag & PARODD)
+                       new_parity = 1;
+       }
+       baud = uart_get_baud_rate(the_port, new_termios, old_termios,
+                                 MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
+       DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __FUNCTION__, baud,
+                               the_port->line));
+
+       if (!the_port->fifosize)
+               the_port->fifosize = FIFO_SIZE;
+       uart_update_timeout(the_port, cflag, baud);
+
+       the_port->ignore_status_mask = N_ALL_INPUT;
+
+       info->tty->low_latency = 1;
+
+       if (I_IGNPAR(info->tty))
+               the_port->ignore_status_mask &= ~(N_PARITY_ERROR
+                                                 | N_FRAMING_ERROR);
+       if (I_IGNBRK(info->tty)) {
+               the_port->ignore_status_mask &= ~N_BREAK;
+               if (I_IGNPAR(info->tty))
+                       the_port->ignore_status_mask &= ~N_OVERRUN_ERROR;
+       }
+       if (!(cflag & CREAD)) {
+               /* ignore everything */
+               the_port->ignore_status_mask &= ~N_DATA_READY;
+       }
+
+       if (cflag & CRTSCTS) {
+               /* enable hardware flow control */
+               port->ip_sscr |= SSCR_HFC_EN;
+       }
+       else {
+               /* disable hardware flow control */
+               port->ip_sscr &= ~SSCR_HFC_EN;
+       }
+       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+
+       /* Set the configuration and proper notification call */
+       DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
+                      "config_port(baud %d data %d stop %d penable %d "
+                       " parity %d), notification 0x%x\n",
+                      __FUNCTION__, (void *)port, the_port->line, cflag, baud,
+                      new_data, new_stop, new_parity_enable, new_parity,
+                      the_port->ignore_status_mask));
+
+       if ((config_port(port, baud,    /* baud */
+                        new_data,      /* byte size */
+                        new_stop,      /* stop bits */
+                        new_parity_enable,     /* set parity */
+                        new_parity)) >= 0) {   /* parity 1==odd */
+               set_notification(port, the_port->ignore_status_mask, 1);
+       }
+}
+
+/**
+ * ic3_startup_local - Start up the serial port - returns >= 0 if no errors
+ * @the_port: Port to operate on
+ */
+static inline int ic3_startup_local(struct uart_port *the_port)
+{
+       struct ioc3_port *port;
+
+       if (!the_port) {
+               NOT_PROGRESS();
+               return -1;
+       }
+
+       port = get_ioc3_port(the_port);
+       if (!port) {
+               NOT_PROGRESS();
+               return -1;
+       }
+
+       local_open(port);
+
+       /* set the protocol */
+       ioc3_set_proto(port, IS_RS232(the_port->line) ? PROTO_RS232 :
+                                                       PROTO_RS422);
+       return 0;
+}
+
+/*
+ * ioc3_cb_output_lowat - called when the output low water mark is hit
+ * @port: port to output
+ */
+static void ioc3_cb_output_lowat(struct ioc3_port *port)
+{
+       unsigned long pflags;
+
+       /* the_port->lock is set on the call here */
+       if (port->ip_port) {
+               spin_lock_irqsave(&port->ip_port->lock, pflags);
+               transmit_chars(port->ip_port);
+               spin_unlock_irqrestore(&port->ip_port->lock, pflags);
+       }
+}
+
+/*
+ * ioc3_cb_post_ncs - called for some basic errors
+ * @port: port to use
+ * @ncs: event
+ */
+static void ioc3_cb_post_ncs(struct uart_port *the_port, int ncs)
+{
+       struct uart_icount *icount;
+
+       icount = &the_port->icount;
+
+       if (ncs & NCS_BREAK)
+               icount->brk++;
+       if (ncs & NCS_FRAMING)
+               icount->frame++;
+       if (ncs & NCS_OVERRUN)
+               icount->overrun++;
+       if (ncs & NCS_PARITY)
+               icount->parity++;
+}
+
+/**
+ * do_read - Read in bytes from the port.  Return the number of bytes
+ *                     actually read.
+ * @the_port: port to use
+ * @buf: place to put the stuff we read
+ * @len: how big 'buf' is
+ */
+
+static inline int do_read(struct uart_port *the_port, char *buf, int len)
+{
+       int prod_ptr, cons_ptr, total;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       struct ring *inring;
+       struct ring_entry *entry;
+       struct port_hooks *hooks = port->ip_hooks;
+       int byte_num;
+       char *sc;
+       int loop_counter;
+
+       BUG_ON(!(len >= 0));
+       BUG_ON(!port);
+
+       /* There is a nasty timing issue in the IOC3. When the rx_timer
+        * expires or the rx_high condition arises, we take an interrupt.
+        * At some point while servicing the interrupt, we read bytes from
+        * the ring buffer and re-arm the rx_timer.  However the rx_timer is
+        * not started until the first byte is received *after* it is armed,
+        * and any bytes pending in the rx construction buffers are not drained
+        * to memory until either there are 4 bytes available or the rx_timer
+        * expires.  This leads to a potential situation where data is left
+        * in the construction buffers forever - 1 to 3 bytes were received
+        * after the interrupt was generated but before the rx_timer was
+        * re-armed. At that point as long as no subsequent bytes are received
+        * the timer will never be started and the bytes will remain in the
+        * construction buffer forever.  The solution is to execute a DRAIN
+        * command after rearming the timer.  This way any bytes received before
+        * the DRAIN will be drained to memory, and any bytes received after
+        * the DRAIN will start the TIMER and be drained when it expires.
+        * Luckily, this only needs to be done when the DMA buffer is empty
+        * since there is no requirement that this function return all
+        * available data as long as it returns some.
+        */
+       /* Re-arm the timer */
+
+       writel(port->ip_rx_cons | SRCIR_ARM, &port->ip_serial_regs->srcir);
+
+       prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+       cons_ptr = port->ip_rx_cons;
+
+       if (prod_ptr == cons_ptr) {
+               int reset_dma = 0;
+
+               /* Input buffer appears empty, do a flush. */
+
+               /* DMA must be enabled for this to work. */
+               if (!(port->ip_sscr & SSCR_DMA_EN)) {
+                       port->ip_sscr |= SSCR_DMA_EN;
+                       reset_dma = 1;
+               }
+
+               /* Potential race condition: we must reload the srpir after
+                * issuing the drain command, otherwise we could think the rx
+                * buffer is empty, then take a very long interrupt, and when
+                * we come back it's full and we wait forever for the drain to
+                * complete.
+                */
+               writel(port->ip_sscr | SSCR_RX_DRAIN,
+                      &port->ip_serial_regs->sscr);
+               prod_ptr = readl(&port->ip_serial_regs->srpir) & PROD_CONS_MASK;
+
+               /* We must not wait for the DRAIN to complete unless there are
+                * at least 8 bytes (2 ring entries) available to receive the
+                * data otherwise the DRAIN will never complete and we'll
+                * deadlock here.
+                * In fact, to make things easier, I'll just ignore the flush if
+                * there is any data at all now available.
+                */
+               if (prod_ptr == cons_ptr) {
+                       loop_counter = 0;
+                       while (readl(&port->ip_serial_regs->sscr) &
+                              SSCR_RX_DRAIN) {
+                               loop_counter++;
+                               if (loop_counter > MAXITER)
+                                       return -1;
+                       }
+
+                       /* SIGH. We have to reload the prod_ptr *again* since
+                        * the drain may have caused it to change
+                        */
+                       prod_ptr = readl(&port->ip_serial_regs->srpir)
+                           & PROD_CONS_MASK;
+               }
+               if (reset_dma) {
+                       port->ip_sscr &= ~SSCR_DMA_EN;
+                       writel(port->ip_sscr, &port->ip_serial_regs->sscr);
+               }
+       }
+       inring = port->ip_inring;
+       port->ip_flags &= ~READ_ABORTED;
+
+       total = 0;
+       loop_counter = 0xfffff; /* to avoid hangs */
+
+       /* Grab bytes from the hardware */
+       while ((prod_ptr != cons_ptr) && (len > 0)) {
+               entry = (struct ring_entry *)((caddr_t) inring + cons_ptr);
+
+               if (loop_counter-- <= 0) {
+                       printk(KERN_WARNING "IOC3 serial: "
+                              "possible hang condition/"
+                              "port stuck on read (line %d).\n",
+                               the_port->line);
+                       break;
+               }
+
+               /* According to the producer pointer, this ring entry
+                * must contain some data.  But if the PIO happened faster
+                * than the DMA, the data may not be available yet, so let's
+                * wait until it arrives.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       /* Indicate the read is aborted so we don't disable
+                        * the interrupt thinking that the consumer is
+                        * congested.
+                        */
+                       port->ip_flags |= READ_ABORTED;
+                       len = 0;
+                       break;
+               }
+
+               /* Load the bytes/status out of the ring entry */
+               for (byte_num = 0; byte_num < 4 && len > 0; byte_num++) {
+                       sc = &(entry->ring_sc[byte_num]);
+
+                       /* Check for change in modem state or overrun */
+                       if ((*sc & RXSB_MODEM_VALID)
+                           && (port->ip_notify & N_DDCD)) {
+                               /* Notify upper layer if DCD dropped */
+                               if ((port->ip_flags & DCD_ON)
+                                   && !(*sc & RXSB_DCD)) {
+                                       /* If we have already copied some data,
+                                        * return it.  We'll pick up the carrier
+                                        * drop on the next pass.  That way we
+                                        * don't throw away the data that has
+                                        * already been copied back to
+                                        * the caller's buffer.
+                                        */
+                                       if (total > 0) {
+                                               len = 0;
+                                               break;
+                                       }
+                                       port->ip_flags &= ~DCD_ON;
+
+                                       /* Turn off this notification so the
+                                        * carrier drop protocol won't see it
+                                        * again when it does a read.
+                                        */
+                                       *sc &= ~RXSB_MODEM_VALID;
+
+                                       /* To keep things consistent, we need
+                                        * to update the consumer pointer so
+                                        * the next reader won't come in and
+                                        * try to read the same ring entries
+                                        * again. This must be done here before
+                                        * the dcd change.
+                                        */
+
+                                       if ((entry->ring_allsc & RING_ANY_VALID)
+                                           == 0) {
+                                               cons_ptr += (int)sizeof
+                                                   (struct ring_entry);
+                                               cons_ptr &= PROD_CONS_MASK;
+                                       }
+                                       writel(cons_ptr,
+                                              &port->ip_serial_regs->srcir);
+                                       port->ip_rx_cons = cons_ptr;
+
+                                       /* Notify upper layer of carrier drop */
+                                       if ((port->ip_notify & N_DDCD)
+                                           && port->ip_port) {
+                                               uart_handle_dcd_change
+                                                       (port->ip_port, 0);
+                                               wake_up_interruptible
+                                                   (&the_port->info->
+                                                    delta_msr_wait);
+                                       }
+
+                                       /* If we had any data to return, we
+                                        * would have returned it above.
+                                        */
+                                       return 0;
+                               }
+                       }
+                       if (*sc & RXSB_MODEM_VALID) {
+                               /* Notify that an input overrun occurred */
+                               if ((*sc & RXSB_OVERRUN)
+                                   && (port->ip_notify & N_OVERRUN_ERROR)) {
+                                       ioc3_cb_post_ncs(the_port, NCS_OVERRUN);
+                               }
+                               /* Don't look at this byte again */
+                               *sc &= ~RXSB_MODEM_VALID;
+                       }
+
+                       /* Check for valid data or RX errors */
+                       if ((*sc & RXSB_DATA_VALID) &&
+                           ((*sc & (RXSB_PAR_ERR
+                                    | RXSB_FRAME_ERR | RXSB_BREAK))
+                            && (port->ip_notify & (N_PARITY_ERROR
+                                                   | N_FRAMING_ERROR
+                                                   | N_BREAK)))) {
+                               /* There is an error condition on the next byte.
+                                * If we have already transferred some bytes,
+                                * we'll stop here. Otherwise if this is the
+                                * first byte to be read, we'll just transfer
+                                * it alone after notifying the
+                                * upper layer of its status.
+                                */
+                               if (total > 0) {
+                                       len = 0;
+                                       break;
+                               } else {
+                                       if ((*sc & RXSB_PAR_ERR) &&
+                                           (port->
+                                            ip_notify & N_PARITY_ERROR)) {
+                                               ioc3_cb_post_ncs(the_port,
+                                                                NCS_PARITY);
+                                       }
+                                       if ((*sc & RXSB_FRAME_ERR) &&
+                                           (port->
+                                            ip_notify & N_FRAMING_ERROR)) {
+                                               ioc3_cb_post_ncs(the_port,
+                                                                NCS_FRAMING);
+                                       }
+                                       if ((*sc & RXSB_BREAK)
+                                           && (port->ip_notify & N_BREAK)) {
+                                               ioc3_cb_post_ncs
+                                                   (the_port, NCS_BREAK);
+                                       }
+                                       len = 1;
+                               }
+                       }
+                       if (*sc & RXSB_DATA_VALID) {
+                               *sc &= ~RXSB_DATA_VALID;
+                               *buf = entry->ring_data[byte_num];
+                               buf++;
+                               len--;
+                               total++;
+                       }
+               }
+
+               /* If we used up this entry entirely, go on to the next one,
+                * otherwise we must have run out of buffer space, so
+                * leave the consumer pointer here for the next read in case
+                * there are still unread bytes in this entry.
+                */
+               if ((entry->ring_allsc & RING_ANY_VALID) == 0) {
+                       cons_ptr += (int)sizeof(struct ring_entry);
+                       cons_ptr &= PROD_CONS_MASK;
+               }
+       }
+
+       /* Update consumer pointer and re-arm rx timer interrupt */
+       writel(cons_ptr, &port->ip_serial_regs->srcir);
+       port->ip_rx_cons = cons_ptr;
+
+       /* If we have now dipped below the rx high water mark and we have
+        * rx_high interrupt turned off, we can now turn it back on again.
+        */
+       if ((port->ip_flags & INPUT_HIGH) && (((prod_ptr - cons_ptr)
+                                              & PROD_CONS_MASK) <
+                                             ((port->
+                                               ip_sscr &
+                                               SSCR_RX_THRESHOLD)
+                                              << PROD_CONS_PTR_OFF))) {
+               port->ip_flags &= ~INPUT_HIGH;
+               enable_intrs(port, hooks->intr_rx_high);
+       }
+       return total;
+}
+
+/**
+ * receive_chars - upper level read.
+ * @the_port: port to read from
+ */
+static int receive_chars(struct uart_port *the_port)
+{
+       struct tty_struct *tty;
+       unsigned char ch[MAX_CHARS];
+       int read_count = 0, read_room, flip = 0;
+       struct uart_info *info = the_port->info;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       unsigned long pflags;
+
+       /* Make sure all the pointers are "good" ones */
+       if (!info)
+               return 0;
+       if (!info->tty)
+               return 0;
+
+       if (!(port->ip_flags & INPUT_ENABLE))
+               return 0;
+
+       spin_lock_irqsave(&the_port->lock, pflags);
+       tty = info->tty;
+
+       read_count = do_read(the_port, ch, MAX_CHARS);
+       if (read_count > 0) {
+               flip = 1;
+               read_room = tty_buffer_request_room(tty, read_count);
+               tty_insert_flip_string(tty, ch, read_room);
+               the_port->icount.rx += read_count;
+       }
+       spin_unlock_irqrestore(&the_port->lock, pflags);
+
+       if (flip)
+               tty_flip_buffer_push(tty);
+
+       return read_count;
+}
+
+/**
+ * ioc3uart_intr_one - lowest level (per port) interrupt handler.
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ * @regs: pt_regs
+ */
+
+static int inline
+ioc3uart_intr_one(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd,
+                       unsigned int pending, struct pt_regs *regs)
+{
+       int port_num = GET_PORT_FROM_SIO_IR(pending);
+       struct port_hooks *hooks;
+       unsigned int rx_high_rd_aborted = 0;
+       unsigned long flags;
+       struct uart_port *the_port;
+       struct ioc3_port *port;
+       int loop_counter;
+       struct ioc3_card *card_ptr;
+       unsigned int sio_ir;
+
+       card_ptr = idd->data[is->id];
+       port = card_ptr->ic_port[port_num].icp_port;
+       hooks = port->ip_hooks;
+
+       /* Possible race condition here: The tx_mt interrupt bit may be
+        * cleared without the intervention of the interrupt handler,
+        * e.g. by a write.  If the top level interrupt handler reads a
+        * tx_mt, then some other processor does a write, starting up
+        * output, then we come in here, see the tx_mt and stop DMA, the
+        * output started by the other processor will hang.  Thus we can
+        * only rely on tx_mt being legitimate if it is read while the
+        * port lock is held.  Therefore this bit must be ignored in the
+        * passed in interrupt mask which was read by the top level
+        * interrupt handler since the port lock was not held at the time
+        * it was read.  We can only rely on this bit being accurate if it
+        * is read while the port lock is held.  So we'll clear it for now,
+        * and reload it later once we have the port lock.
+        */
+
+       sio_ir = pending & ~(hooks->intr_tx_mt);
+       spin_lock_irqsave(&port->ip_lock, flags);
+
+       loop_counter = MAXITER; /* to avoid hangs */
+
+       do {
+               uint32_t shadow;
+
+               if (loop_counter-- <= 0) {
+                       printk(KERN_WARNING "IOC3 serial: "
+                              "possible hang condition/"
+                              "port stuck on interrupt (line %d).\n",
+                               ((struct uart_port *)port->ip_port)->line);
+                       break;
+               }
+               /* Handle a DCD change */
+               if (sio_ir & hooks->intr_delta_dcd) {
+                       ioc3_ack(is, idd, hooks->intr_delta_dcd);
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DDCD)
+                           && (shadow & SHADOW_DCD)
+                           && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               uart_handle_dcd_change(the_port,
+                                               shadow & SHADOW_DCD);
+                               wake_up_interruptible
+                                   (&the_port->info->delta_msr_wait);
+                       } else if ((port->ip_notify & N_DDCD)
+                                  && !(shadow & SHADOW_DCD)) {
+                               /* Flag delta DCD/no DCD */
+                               uart_handle_dcd_change(port->ip_port,
+                                               shadow & SHADOW_DCD);
+                               port->ip_flags |= DCD_ON;
+                       }
+               }
+
+               /* Handle a CTS change */
+               if (sio_ir & hooks->intr_delta_cts) {
+                       ioc3_ack(is, idd, hooks->intr_delta_cts);
+                       shadow = readl(&port->ip_serial_regs->shadow);
+
+                       if ((port->ip_notify & N_DCTS) && (port->ip_port)) {
+                               the_port = port->ip_port;
+                               uart_handle_cts_change(the_port, shadow
+                                               & SHADOW_CTS);
+                               wake_up_interruptible
+                                   (&the_port->info->delta_msr_wait);
+                       }
+               }
+
+               /* rx timeout interrupt.  Must be some data available.  Put this
+                * before the check for rx_high since servicing this condition
+                * may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_rx_timer) {
+                       ioc3_ack(is, idd, hooks->intr_rx_timer);
+                       if ((port->ip_notify & N_DATA_READY)
+                                               && (port->ip_port)) {
+                               receive_chars(port->ip_port);
+                       }
+               }
+
+               /* rx high interrupt. Must be after rx_timer.  */
+               else if (sio_ir & hooks->intr_rx_high) {
+                       /* Data available, notify upper layer */
+                       if ((port->ip_notify & N_DATA_READY) && port->ip_port) {
+                               receive_chars(port->ip_port);
+                       }
+
+                       /* We can't ACK this interrupt.  If receive_chars didn't
+                        * cause the condition to clear, we'll have to disable
+                        * the interrupt until the data is drained.
+                        * If the read was aborted, don't disable the interrupt
+                        * as this may cause us to hang indefinitely.  An
+                        * aborted read generally means that this interrupt
+                        * hasn't been delivered to the cpu yet anyway, even
+                        * though we see it as asserted when we read the sio_ir.
+                        */
+                       if ((sio_ir = PENDING(card_ptr, idd))
+                                       & hooks->intr_rx_high) {
+                               if (port->ip_flags & READ_ABORTED) {
+                                       rx_high_rd_aborted++;
+                               }
+                               else {
+                                       card_ptr->ic_enable &= ~hooks->intr_rx_high;
+                                       port->ip_flags |= INPUT_HIGH;
+                               }
+                       }
+               }
+
+               /* We got a low water interrupt: notify upper layer to
+                * send more data.  Must come before tx_mt since servicing
+                * this condition may cause that condition to clear.
+                */
+               if (sio_ir & hooks->intr_tx_explicit) {
+                       port->ip_flags &= ~LOWAT_WRITTEN;
+                       ioc3_ack(is, idd, hooks->intr_tx_explicit);
+                       if (port->ip_notify & N_OUTPUT_LOWAT)
+                               ioc3_cb_output_lowat(port);
+               }
+
+               /* Handle tx_mt.  Must come after tx_explicit.  */
+               else if (sio_ir & hooks->intr_tx_mt) {
+                       /* If we are expecting a lowat notification
+                        * and we get to this point it probably means that for
+                        * some reason the tx_explicit didn't work as expected
+                        * (that can legitimately happen if the output buffer is
+                        * filled up in just the right way).
+                        * So send the notification now.
+                        */
+                       if (port->ip_notify & N_OUTPUT_LOWAT) {
+                               ioc3_cb_output_lowat(port);
+
+                               /* We need to reload the sio_ir since the lowat
+                                * call may have caused another write to occur,
+                                * clearing the tx_mt condition.
+                                */
+                               sio_ir = PENDING(card_ptr, idd);
+                       }
+
+                       /* If the tx_mt condition still persists even after the
+                        * lowat call, we've got some work to do.
+                        */
+                       if (sio_ir & hooks->intr_tx_mt) {
+                               /* If we are not currently expecting DMA input,
+                                * and the transmitter has just gone idle,
+                                * there is no longer any reason for DMA, so
+                                * disable it.
+                                */
+                               if (!(port->ip_notify
+                                     & (N_DATA_READY | N_DDCD))) {
+                                       BUG_ON(!(port->ip_sscr
+                                                & SSCR_DMA_EN));
+                                       port->ip_sscr &= ~SSCR_DMA_EN;
+                                       writel(port->ip_sscr,
+                                              &port->ip_serial_regs->sscr);
+                               }
+                               /* Prevent infinite tx_mt interrupt */
+                               card_ptr->ic_enable &= ~hooks->intr_tx_mt;
+                       }
+               }
+               sio_ir = PENDING(card_ptr, idd);
+
+               /* if the read was aborted and only hooks->intr_rx_high,
+                * clear hooks->intr_rx_high, so we do not loop forever.
+                */
+
+               if (rx_high_rd_aborted && (sio_ir == hooks->intr_rx_high)) {
+                       sio_ir &= ~hooks->intr_rx_high;
+               }
+       } while (sio_ir & hooks->intr_all);
+
+       spin_unlock_irqrestore(&port->ip_lock, flags);
+       ioc3_enable(is, idd, card_ptr->ic_enable);
+       return 0;
+}
+
+/**
+ * ioc3uart_intr - field all serial interrupts
+ * @is : submodule
+ * @idd: driver data
+ * @pending: interrupts to handle
+ * @regs: pt_regs
+ *
+ */
+
+static int ioc3uart_intr(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd,
+                       unsigned int pending, struct pt_regs *regs)
+{
+       int ret = 0;
+
+       /*
+        * The upper level interrupt handler sends interrupts for both ports
+        * here. So we need to call for each port with its interrupts.
+        */
+
+       if (pending & SIO_IR_SA)
+               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA, regs);
+       if (pending & SIO_IR_SB)
+               ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB, regs);
+
+       return ret;
+}
+
+/**
+ * ic3_type
+ * @port: Port to operate with (we ignore since we only have one port)
+ *
+ */
+static const char *ic3_type(struct uart_port *the_port)
+{
+       if (IS_RS232(the_port->line))
+               return "SGI IOC3 Serial [rs232]";
+       else
+               return "SGI IOC3 Serial [rs422]";
+}
+
+/**
+ * ic3_tx_empty - Is the transmitter empty?
+ * @port: Port to operate on
+ *
+ */
+static unsigned int ic3_tx_empty(struct uart_port *the_port)
+{
+       unsigned int ret = 0;
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (readl(&port->ip_serial_regs->shadow) & SHADOW_TEMT)
+               ret = TIOCSER_TEMT;
+       return ret;
+}
+
+/**
+ * ic3_stop_tx - stop the transmitter
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_tx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port)
+               set_notification(port, N_OUTPUT_LOWAT, 0);
+}
+
+/**
+ * ic3_stop_rx - stop the receiver
+ * @port: Port to operate on
+ *
+ */
+static void ic3_stop_rx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port)
+               port->ip_flags &= ~INPUT_ENABLE;
+}
+
+/**
+ * null_void_function
+ * @port: Port to operate on
+ *
+ */
+static void null_void_function(struct uart_port *the_port)
+{
+}
+
+/**
+ * ic3_shutdown - shut down the port - free irq and disable
+ * @port: port to shut down
+ *
+ */
+static void ic3_shutdown(struct uart_port *the_port)
+{
+       unsigned long port_flags;
+       struct ioc3_port *port;
+       struct uart_info *info;
+
+       port = get_ioc3_port(the_port);
+       if (!port)
+               return;
+
+       info = the_port->info;
+       wake_up_interruptible(&info->delta_msr_wait);
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       set_notification(port, N_ALL, 0);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_set_mctrl - set control lines (dtr, rts, etc)
+ * @port: Port to operate on
+ * @mctrl: Lines to set/unset
+ *
+ */
+static void ic3_set_mctrl(struct uart_port *the_port, unsigned int mctrl)
+{
+       unsigned char mcr = 0;
+
+       if (mctrl & TIOCM_RTS)
+               mcr |= UART_MCR_RTS;
+       if (mctrl & TIOCM_DTR)
+               mcr |= UART_MCR_DTR;
+       if (mctrl & TIOCM_OUT1)
+               mcr |= UART_MCR_OUT1;
+       if (mctrl & TIOCM_OUT2)
+               mcr |= UART_MCR_OUT2;
+       if (mctrl & TIOCM_LOOP)
+               mcr |= UART_MCR_LOOP;
+
+       set_mcr(the_port, mcr, SHADOW_DTR);
+}
+
+/**
+ * ic3_get_mctrl - get control line info
+ * @port: port to operate on
+ *
+ */
+static unsigned int ic3_get_mctrl(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+       uint32_t shadow;
+       unsigned int ret = 0;
+
+       if (!port)
+               return 0;
+
+       shadow = readl(&port->ip_serial_regs->shadow);
+       if (shadow & SHADOW_DCD)
+               ret |= TIOCM_CD;
+       if (shadow & SHADOW_DR)
+               ret |= TIOCM_DSR;
+       if (shadow & SHADOW_CTS)
+               ret |= TIOCM_CTS;
+       return ret;
+}
+
+/**
+ * ic3_start_tx - Start transmitter. Called with the_port->lock
+ * @port: Port to operate on
+ *
+ */
+static void ic3_start_tx(struct uart_port *the_port)
+{
+       struct ioc3_port *port = get_ioc3_port(the_port);
+
+       if (port) {
+               set_notification(port, N_OUTPUT_LOWAT, 1);
+               enable_intrs(port, port->ip_hooks->intr_tx_mt);
+       }
+}
+
+/**
+ * ic3_break_ctl - handle breaks
+ * @port: Port to operate on
+ * @break_state: Break state
+ *
+ */
+static void ic3_break_ctl(struct uart_port *the_port, int break_state)
+{
+}
+
+/**
+ * ic3_startup - Start up the serial port - always return 0 (We're always on)
+ * @port: Port to operate on
+ *
+ */
+static int ic3_startup(struct uart_port *the_port)
+{
+       int retval;
+       struct ioc3_port *port;
+       struct ioc3_card *card_ptr;
+       unsigned long port_flags;
+
+       if (!the_port) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+       port = get_ioc3_port(the_port);
+       if (!port) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+       card_ptr = port->ip_card;
+       port->ip_port = the_port;
+
+       if (!card_ptr) {
+               NOT_PROGRESS();
+               return -ENODEV;
+       }
+
+       /* Start up the serial port */
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       retval = ic3_startup_local(the_port);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+       return retval;
+}
+
+/**
+ * ic3_set_termios - set termios stuff
+ * @port: port to operate on
+ * @termios: New settings
+ * @termios: Old
+ *
+ */
+static void
+ic3_set_termios(struct uart_port *the_port,
+               struct termios *termios, struct termios *old_termios)
+{
+       unsigned long port_flags;
+
+       spin_lock_irqsave(&the_port->lock, port_flags);
+       ioc3_change_speed(the_port, termios, old_termios);
+       spin_unlock_irqrestore(&the_port->lock, port_flags);
+}
+
+/**
+ * ic3_request_port - allocate resources for port - no op....
+ * @port: port to operate on
+ *
+ */
+static int ic3_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/* Associate the uart functions above - given to serial core */
+static struct uart_ops ioc3_ops = {
+       .tx_empty = ic3_tx_empty,
+       .set_mctrl = ic3_set_mctrl,
+       .get_mctrl = ic3_get_mctrl,
+       .stop_tx = ic3_stop_tx,
+       .start_tx = ic3_start_tx,
+       .stop_rx = ic3_stop_rx,
+       .enable_ms = null_void_function,
+       .break_ctl = ic3_break_ctl,
+       .startup = ic3_startup,
+       .shutdown = ic3_shutdown,
+       .set_termios = ic3_set_termios,
+       .type = ic3_type,
+       .release_port = null_void_function,
+       .request_port = ic3_request_port,
+};
+
+/*
+ * Boot-time initialization code
+ */
+
+static struct uart_driver ioc3_uart = {
+       .owner = THIS_MODULE,
+       .driver_name = "ioc3_serial",
+       .dev_name = DEVICE_NAME,
+       .major = DEVICE_MAJOR,
+       .minor = DEVICE_MINOR,
+       .nr = MAX_LOGICAL_PORTS
+};
+
+/**
+ * ioc3_serial_core_attach - register with serial core
+ *             This is done during pci probing
+ * @is: submodule struct for this
+ * @idd: handle for this card
+ */
+static inline int ioc3_serial_core_attach( struct ioc3_submodule *is,
+                               struct ioc3_driver_data *idd)
+{
+       struct ioc3_port *port;
+       struct uart_port *the_port;
+       struct ioc3_card *card_ptr = idd->data[is->id];
+       int ii, phys_port;
+       struct pci_dev *pdev = idd->pdev;
+
+       DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
+                      __FUNCTION__, pdev, (void *)card_ptr));
+
+       if (!card_ptr)
+               return -ENODEV;
+
+       /* once around for each logical port on this card */
+       for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+               phys_port = GET_PHYSICAL_PORT(ii);
+               the_port = &card_ptr->ic_port[phys_port].
+                               icp_uart_port[GET_LOGICAL_PORT(ii)];
+               port = card_ptr->ic_port[phys_port].icp_port;
+               port->ip_port = the_port;
+
+               DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
+                       __FUNCTION__, (void *)the_port, (void *)port,
+                               phys_port, ii));
+
+               /* membase, iobase and mapbase just need to be non-0 */
+               the_port->membase = (unsigned char __iomem *)1;
+               the_port->iobase = (pdev->bus->number << 16) |  ii;
+               the_port->line = (Num_of_ioc3_cards << 2) | ii;
+               the_port->mapbase = 1;
+               the_port->type = PORT_16550A;
+               the_port->fifosize = FIFO_SIZE;
+               the_port->ops = &ioc3_ops;
+               the_port->irq = idd->irq_io;
+               the_port->dev = &pdev->dev;
+
+               if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
+                       printk(KERN_WARNING
+                         "%s: unable to add port %d bus %d\n",
+                              __FUNCTION__, the_port->line, pdev->bus->number);
+               } else {
+                       DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
+                         the_port->line, the_port->irq, pdev->bus->number));
+               }
+
+               /* all ports are rs232 for now */
+               if (IS_PHYSICAL_PORT(ii))
+                       ioc3_set_proto(port, PROTO_RS232);
+       }
+       return 0;
+}
+
+/**
+ * ioc3uart_remove - register detach function
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this submodule
+ */
+
+static int ioc3uart_remove(struct ioc3_submodule *is,
+                       struct ioc3_driver_data *idd)
+{
+       struct ioc3_card *card_ptr = idd->data[is->id];
+       struct uart_port *the_port;
+       struct ioc3_port *port;
+       int ii;
+
+       if (card_ptr) {
+               for (ii = 0; ii < LOGICAL_PORTS_PER_CARD; ii++) {
+                       the_port = &card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+                                       icp_uart_port[GET_LOGICAL_PORT(ii)];
+                       if (the_port)
+                               uart_remove_one_port(&ioc3_uart, the_port);
+                       port = card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].icp_port;
+                       if (port && IS_PHYSICAL_PORT(ii)
+                                       && (GET_PHYSICAL_PORT(ii) == 0)) {
+                               pci_free_consistent(port->ip_idd->pdev,
+                                       TOTAL_RING_BUF_SIZE,
+                                       (void *)port->ip_cpu_ringbuf,
+                                       port->ip_dma_ringbuf);
+                               kfree(port);
+                               card_ptr->ic_port[GET_PHYSICAL_PORT(ii)].
+                                                       icp_port = NULL;
+                       }
+               }
+               kfree(card_ptr);
+               idd->data[is->id] = NULL;
+       }
+       return 0;
+}
+
+/**
+ * ioc3uart_probe - card probe function called from shim driver
+ * @is: submodule struct for this submodule
+ * @idd: ioc3 driver data for this card
+ */
+
+static int __devinit
+ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
+{
+       struct pci_dev *pdev = idd->pdev;
+       struct ioc3_card *card_ptr;
+       int ret = 0;
+       struct ioc3_port *port;
+       struct ioc3_port *ports[PORTS_PER_CARD];
+       int phys_port;
+
+       DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd));
+
+       card_ptr = kmalloc(sizeof(struct ioc3_card), GFP_KERNEL);
+       if (!card_ptr) {
+               printk(KERN_WARNING "ioc3_attach_one"
+                      ": unable to get memory for the IOC3\n");
+               return -ENOMEM;
+       }
+       memset(card_ptr, 0, sizeof(struct ioc3_card));
+       idd->data[is->id] = card_ptr;
+       Submodule_slot = is->id;
+
+       writel(((UARTA_BASE >> 3) << SIO_CR_SER_A_BASE_SHIFT) |
+               ((UARTB_BASE >> 3) << SIO_CR_SER_B_BASE_SHIFT) |
+               (0xf << SIO_CR_CMD_PULSE_SHIFT), &idd->vma->sio_cr);
+
+       pci_write_config_dword(pdev, PCI_LAT, 0xff00);
+
+       /* Enable serial port mode select generic PIO pins as outputs */
+       ioc3_gpcr_set(idd, GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL);
+
+       /* Create port structures for each port */
+       for (phys_port = 0; phys_port < PORTS_PER_CARD; phys_port++) {
+               port = kmalloc(sizeof(struct ioc3_port), GFP_KERNEL);
+               if (!port) {
+                       printk(KERN_WARNING
+                              "IOC3 serial memory not available for port\n");
+                       goto out4;
+               }
+               memset(port, 0, sizeof(struct ioc3_port));
+               spin_lock_init(&port->ip_lock);
+
+               /* we need to remember the previous ones, to point back to
+                * them farther down - setting up the ring buffers.
+                */
+               ports[phys_port] = port;
+
+               /* init to something useful */
+               card_ptr->ic_port[phys_port].icp_port = port;
+               port->ip_is = is;
+               port->ip_idd = idd;
+               port->ip_baud = 9600;
+               port->ip_card = card_ptr;
+               port->ip_hooks = &hooks_array[phys_port];
+
+               /* Setup each port */
+               if (phys_port == 0) {
+                       port->ip_serial_regs = &idd->vma->port_a;
+                       port->ip_uart_regs = &idd->vma->sregs.uarta;
+
+                       DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
+                                      "ip_uart_regs 0x%p\n",
+                                      __FUNCTION__,
+                                      (void *)port->ip_serial_regs,
+                                      (void *)port->ip_uart_regs));
+
+                       /* setup ring buffers */
+                       port->ip_cpu_ringbuf = pci_alloc_consistent(pdev,
+                               TOTAL_RING_BUF_SIZE, &port->ip_dma_ringbuf);
+
+                       BUG_ON(!((((int64_t) port->ip_dma_ringbuf) &
+                                 (TOTAL_RING_BUF_SIZE - 1)) == 0));
+                       port->ip_inring = RING(port, RX_A);
+                       port->ip_outring = RING(port, TX_A);
+                       DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
+                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+                                       "ip_outring 0x%p\n",
+                                      __FUNCTION__,
+                                      (void *)port->ip_cpu_ringbuf,
+                                      (void *)port->ip_dma_ringbuf,
+                                      (void *)port->ip_inring,
+                                      (void *)port->ip_outring));
+               }
+               else {
+                       port->ip_serial_regs = &idd->vma->port_b;
+                       port->ip_uart_regs = &idd->vma->sregs.uartb;
+
+                       DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
+                                      "ip_uart_regs 0x%p\n",
+                                      __FUNCTION__,
+                                      (void *)port->ip_serial_regs,
+                                      (void *)port->ip_uart_regs));
+
+                       /* share the ring buffers */
+                       port->ip_dma_ringbuf =
+                           ports[phys_port - 1]->ip_dma_ringbuf;
+                       port->ip_cpu_ringbuf =
+                           ports[phys_port - 1]->ip_cpu_ringbuf;
+                       port->ip_inring = RING(port, RX_B);
+                       port->ip_outring = RING(port, TX_B);
+                       DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
+                                      "ip_dma_ringbuf 0x%p, ip_inring 0x%p "
+                                       "ip_outring 0x%p\n",
+                                      __FUNCTION__,
+                                      (void *)port->ip_cpu_ringbuf,
+                                      (void *)port->ip_dma_ringbuf,
+                                      (void *)port->ip_inring,
+                                      (void *)port->ip_outring));
+               }
+
+               DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
+                              __FUNCTION__,
+                              phys_port, (void *)port, (void *)card_ptr));
+               DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
+                              (void *)port->ip_serial_regs,
+                              (void *)port->ip_uart_regs));
+
+               /* Initialize the hardware for IOC3 */
+               port_init(port);
+
+               DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
+                              "outring 0x%p\n",
+                              __FUNCTION__,
+                              phys_port, (void *)port,
+                              (void *)port->ip_inring,
+                              (void *)port->ip_outring));
+
+       }
+
+       /* register port with the serial core */
+
+       if ((ret = ioc3_serial_core_attach(is, idd)))
+               goto out4;
+
+       Num_of_ioc3_cards++;
+
+       return ret;
+
+       /* error exits that give back resources */
+out4:
+       kfree(card_ptr);
+       return ret;
+}
+
+static struct ioc3_submodule ioc3uart_submodule = {
+       .name = "IOC3uart",
+       .probe = ioc3uart_probe,
+       .remove = ioc3uart_remove,
+       /* call .intr for both ports initially */
+       .irq_mask = SIO_IR_SA | SIO_IR_SB,
+       .intr = ioc3uart_intr,
+       .owner = THIS_MODULE,
+};
+
+/**
+ * ioc3_detect - module init called,
+ */
+static int __devinit ioc3uart_init(void)
+{
+       int ret;
+
+       /* register with serial core */
+       if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
+               printk(KERN_WARNING
+                      "%s: Couldn't register IOC3 uart serial driver\n",
+                      __FUNCTION__);
+               return ret;
+       }
+       ret = ioc3_register_submodule(&ioc3uart_submodule);
+       if (ret)
+               uart_unregister_driver(&ioc3_uart);
+       return ret;
+}
+
+static void __devexit ioc3uart_exit(void)
+{
+       ioc3_unregister_submodule(&ioc3uart_submodule);
+       uart_unregister_driver(&ioc3_uart);
+}
+
+module_init(ioc3uart_init);
+module_exit(ioc3uart_exit);
+
+MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
+MODULE_DESCRIPTION("Serial PCI driver module for SGI IOC3 card");
+MODULE_LICENSE("GPL");
index 5f52883e64d2ade773b968edd967e395121a58bd..4e03a87f3fb48df3f70b505a2b89bb86f91b4584 100644 (file)
@@ -69,7 +69,6 @@
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
 #include <asm/macio.h>
-#include <asm/semaphore.h>
 
 #if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -1593,7 +1592,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
        state = pmz_uart_reg.state + uap->port.line;
 
        mutex_lock(&pmz_irq_mutex);
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        spin_lock_irqsave(&uap->port.lock, flags);
 
@@ -1624,7 +1623,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
        /* Shut the chip down */
        pmz_set_scc_power(uap, 0);
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        mutex_unlock(&pmz_irq_mutex);
 
        pmz_debug("suspend, switching complete\n");
@@ -1653,7 +1652,7 @@ static int pmz_resume(struct macio_dev *mdev)
        state = pmz_uart_reg.state + uap->port.line;
 
        mutex_lock(&pmz_irq_mutex);
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        spin_lock_irqsave(&uap->port.lock, flags);
        if (!ZS_IS_OPEN(uap) && !ZS_IS_CONS(uap)) {
@@ -1685,7 +1684,7 @@ static int pmz_resume(struct macio_dev *mdev)
        }
 
  bail:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        mutex_unlock(&pmz_irq_mutex);
 
        /* Right now, we deal with delay by blocking here, I'll be
index 2ca620900bcc24cf9b6f18850853597ddbbdaab2..943770470b9db316af2ed25cce1fca9296df43a2 100644 (file)
@@ -638,7 +638,7 @@ static int uart_set_info(struct uart_state *state,
         * module insertion/removal doesn't change anything
         * under us.
         */
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        change_irq  = new_serial.irq != port->irq;
 
@@ -797,7 +797,7 @@ static int uart_set_info(struct uart_state *state,
        } else
                retval = uart_startup(state, 1);
  exit:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        return retval;
 }
 
@@ -834,7 +834,7 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
        struct uart_port *port = state->port;
        int result = -EIO;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
        if ((!file || !tty_hung_up_p(file)) &&
            !(tty->flags & (1 << TTY_IO_ERROR))) {
                result = port->mctrl;
@@ -843,7 +843,7 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
                result |= port->ops->get_mctrl(port);
                spin_unlock_irq(&port->lock);
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        return result;
 }
@@ -856,13 +856,13 @@ uart_tiocmset(struct tty_struct *tty, struct file *file,
        struct uart_port *port = state->port;
        int ret = -EIO;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
        if ((!file || !tty_hung_up_p(file)) &&
            !(tty->flags & (1 << TTY_IO_ERROR))) {
                uart_update_mctrl(port, set, clear);
                ret = 0;
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        return ret;
 }
 
@@ -873,12 +873,12 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
 
        BUG_ON(!kernel_locked());
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (port->type != PORT_UNKNOWN)
                port->ops->break_ctl(port, break_state);
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 static int uart_do_autoconfig(struct uart_state *state)
@@ -894,7 +894,7 @@ static int uart_do_autoconfig(struct uart_state *state)
         * changing, and hence any extra opens of the port while
         * we're auto-configuring.
         */
-       if (down_interruptible(&state->sem))
+       if (mutex_lock_interruptible(&state->mutex))
                return -ERESTARTSYS;
 
        ret = -EBUSY;
@@ -920,7 +920,7 @@ static int uart_do_autoconfig(struct uart_state *state)
 
                ret = uart_startup(state, 1);
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
        return ret;
 }
 
@@ -1074,7 +1074,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
        if (ret != -ENOIOCTLCMD)
                goto out;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (tty_hung_up_p(filp)) {
                ret = -EIO;
@@ -1098,7 +1098,7 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
        }
        }
  out_up:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
  out:
        return ret;
 }
@@ -1186,7 +1186,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
 
        DPRINTK("uart_close(%d) called\n", port->line);
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (tty_hung_up_p(filp))
                goto done;
@@ -1260,7 +1260,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        wake_up_interruptible(&state->info->open_wait);
 
  done:
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
@@ -1334,7 +1334,7 @@ static void uart_hangup(struct tty_struct *tty)
        BUG_ON(!kernel_locked());
        DPRINTK("uart_hangup(%d)\n", state->port->line);
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
        if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
                uart_flush_buffer(tty);
                uart_shutdown(state);
@@ -1344,7 +1344,7 @@ static void uart_hangup(struct tty_struct *tty)
                wake_up_interruptible(&state->info->open_wait);
                wake_up_interruptible(&state->info->delta_msr_wait);
        }
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 /*
@@ -1447,9 +1447,9 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
                if (mctrl & TIOCM_CAR)
                        break;
 
-               up(&state->sem);
+               mutex_unlock(&state->mutex);
                schedule();
-               down(&state->sem);
+               mutex_lock(&state->mutex);
 
                if (signal_pending(current))
                        break;
@@ -1475,7 +1475,7 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
 
        mutex_lock(&port_mutex);
        state = drv->state + line;
-       if (down_interruptible(&state->sem)) {
+       if (mutex_lock_interruptible(&state->mutex)) {
                state = ERR_PTR(-ERESTARTSYS);
                goto out;
        }
@@ -1483,7 +1483,7 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
        state->count++;
        if (!state->port) {
                state->count--;
-               up(&state->sem);
+               mutex_unlock(&state->mutex);
                state = ERR_PTR(-ENXIO);
                goto out;
        }
@@ -1504,7 +1504,7 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
                                     (unsigned long)state);
                } else {
                        state->count--;
-                       up(&state->sem);
+                       mutex_unlock(&state->mutex);
                        state = ERR_PTR(-ENOMEM);
                }
        }
@@ -1571,7 +1571,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
        if (tty_hung_up_p(filp)) {
                retval = -EAGAIN;
                state->count--;
-               up(&state->sem);
+               mutex_unlock(&state->mutex);
                goto fail;
        }
 
@@ -1591,7 +1591,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
         */
        if (retval == 0)
                retval = uart_block_til_ready(filp, state);
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        /*
         * If this is the first open to succeed, adjust things to suit.
@@ -1867,7 +1867,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 {
        struct uart_state *state = drv->state + port->line;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        if (state->info && state->info->flags & UIF_INITIALIZED) {
                struct uart_ops *ops = port->ops;
@@ -1896,7 +1896,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
 
        uart_change_pm(state, 3);
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        return 0;
 }
@@ -1905,7 +1905,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
 {
        struct uart_state *state = drv->state + port->line;
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        uart_change_pm(state, 0);
 
@@ -1954,7 +1954,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
                }
        }
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 
        return 0;
 }
@@ -2049,7 +2049,7 @@ uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
        if (info && info->tty)
                tty_vhangup(info->tty);
 
-       down(&state->sem);
+       mutex_lock(&state->mutex);
 
        state->info = NULL;
 
@@ -2072,7 +2072,7 @@ uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
                kfree(info);
        }
 
-       up(&state->sem);
+       mutex_unlock(&state->mutex);
 }
 
 static struct tty_operations uart_ops = {
@@ -2161,7 +2161,7 @@ int uart_register_driver(struct uart_driver *drv)
                state->close_delay     = 500;   /* .5 seconds */
                state->closing_wait    = 30000; /* 30 seconds */
 
-               init_MUTEX(&state->sem);
+               mutex_init(&state->mutex);
        }
 
        retval = tty_register_driver(normal);
index 7bdab2a7f59c61f25f7dd8b6b44c1b10e5ff6b42..94b22903119841369dcae3779c55eaeb36fce066 100644 (file)
@@ -175,8 +175,6 @@ int superhyway_register_driver(struct superhyway_driver *drv)
 {
        drv->drv.name   = drv->name;
        drv->drv.bus    = &superhyway_bus_type;
-       drv->drv.probe  = superhyway_device_probe;
-       drv->drv.remove = superhyway_device_remove;
 
        return driver_register(&drv->drv);
 }
@@ -213,6 +211,8 @@ struct bus_type superhyway_bus_type = {
 #ifdef CONFIG_SYSFS
        .dev_attrs      = superhyway_dev_attrs,
 #endif
+       .probe          = superhyway_device_probe,
+       .remove         = superhyway_device_remove,
 };
 
 static int __init superhyway_bus_init(void)
index 13b8d249da5c7d7d3f4eb60fee24a8525e951d2d..d95265b187a3d30f1a95368389f6bcaf77d1981e 100644 (file)
@@ -17,4 +17,18 @@ config SGI_IOC4
        If you have an SGI Altix with an IOC4-based
        I/O controller say Y.  Otherwise say N.
 
+config SGI_IOC3
+       tristate "SGI IOC3 Base IO support"
+       depends on (IA64_GENERIC || IA64_SGI_SN2)
+       default m
+       ---help---
+       This option enables basic support for the SGI IOC3-based Base IO
+       controller card.  This option does not enable any specific
+       functions on such a card, but provides necessary infrastructure
+       for other drivers to utilize.
+
+       If you have an SGI Altix with an IOC3-based
+       I/O controller or a PCI IOC3 serial card say Y.
+       Otherwise say N.
+
 endmenu
index c2a2841853727d0cf02baa87e0d260ffac1114de..2cda011597c0e018ea931a2393f59526effeba9a 100644 (file)
@@ -4,3 +4,4 @@
 #
 
 obj-$(CONFIG_SGI_IOC4) += ioc4.o
+obj-$(CONFIG_SGI_IOC3) += ioc3.o
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
new file mode 100644 (file)
index 0000000..aaa009f
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ * SGI IOC3 master driver and IRQ demuxer
+ *
+ * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
+ * Heavily based on similar work by:
+ *   Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
+ *   Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ioc3.h>
+#include <linux/rwsem.h>
+
+#define IOC3_PCI_SIZE 0x100000
+
+static LIST_HEAD(ioc3_devices);
+static int ioc3_counter;
+static DECLARE_RWSEM(ioc3_devices_rwsem);
+
+static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
+static struct ioc3_submodule *ioc3_ethernet;
+static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED;
+
+/* NIC probing code */
+
+#define GPCR_MLAN_EN    0x00200000      /* enable MCR to pin 8 */
+
+static inline unsigned mcr_pack(unsigned pulse, unsigned sample)
+{
+       return (pulse << 10) | (sample << 2);
+}
+
+static int nic_wait(struct ioc3_driver_data *idd)
+{
+       volatile unsigned mcr;
+
+        do {
+                mcr = (volatile unsigned)idd->vma->mcr;
+        } while (!(mcr & 2));
+
+        return mcr & 1;
+}
+
+static int nic_reset(struct ioc3_driver_data *idd)
+{
+        int presence;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       idd->vma->mcr = mcr_pack(500, 65);
+       presence = nic_wait(idd);
+       local_irq_restore(flags);
+
+       udelay(500);
+
+        return presence;
+}
+
+static inline int nic_read_bit(struct ioc3_driver_data *idd)
+{
+       int result;
+       unsigned long flags;
+
+       local_irq_save(flags);
+       idd->vma->mcr = mcr_pack(6, 13);
+       result = nic_wait(idd);
+       local_irq_restore(flags);
+
+       udelay(500);
+
+       return result;
+}
+
+static inline void nic_write_bit(struct ioc3_driver_data *idd, int bit)
+{
+       if (bit)
+               idd->vma->mcr = mcr_pack(6, 110);
+       else
+               idd->vma->mcr = mcr_pack(80, 30);
+
+       nic_wait(idd);
+}
+
+static unsigned nic_read_byte(struct ioc3_driver_data *idd)
+{
+       unsigned result = 0;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               result = (result >> 1) | (nic_read_bit(idd) << 7);
+
+       return result;
+}
+
+static void nic_write_byte(struct ioc3_driver_data *idd, int byte)
+{
+       int i, bit;
+
+       for (i = 8; i; i--) {
+               bit = byte & 1;
+               byte >>= 1;
+
+               nic_write_bit(idd, bit);
+       }
+}
+
+static unsigned long
+nic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr)
+{
+       int a, b, index, disc;
+
+       nic_reset(idd);
+
+       /* Search ROM.  */
+       nic_write_byte(idd, 0xF0);
+
+       /* Algorithm from ``Book of iButton Standards''.  */
+       for (index = 0, disc = 0; index < 64; index++) {
+               a = nic_read_bit(idd);
+               b = nic_read_bit(idd);
+
+               if (a && b) {
+                       printk(KERN_WARNING "IOC3 NIC search failed.\n");
+                       *last = 0;
+                       return 0;
+               }
+
+               if (!a && !b) {
+                       if (index == *last) {
+                               addr |= 1UL << index;
+                       } else if (index > *last) {
+                               addr &= ~(1UL << index);
+                               disc = index;
+                       } else if ((addr & (1UL << index)) == 0)
+                               disc = index;
+                       nic_write_bit(idd, (addr>>index)&1);
+                       continue;
+               } else {
+                       if (a)
+                               addr |= 1UL << index;
+                       else
+                               addr &= ~(1UL << index);
+                       nic_write_bit(idd, a);
+                       continue;
+               }
+       }
+       *last = disc;
+       return addr;
+}
+
+static void nic_addr(struct ioc3_driver_data *idd, unsigned long addr)
+{
+       int index;
+
+       nic_reset(idd);
+       nic_write_byte(idd, 0xF0);
+       for (index = 0; index < 64; index++) {
+               nic_read_bit(idd);
+               nic_read_bit(idd);
+               nic_write_bit(idd, (addr>>index)&1);
+       }
+}
+
+static void crc16_byte(unsigned int *crc, unsigned char db)
+{
+       int i;
+
+       for(i=0;i<8;i++) {
+               *crc <<= 1;
+               if((db^(*crc>>16)) & 1)
+                       *crc ^= 0x8005;
+               db >>= 1;
+       }
+       *crc &= 0xFFFF;
+}
+
+static unsigned int crc16_area(unsigned char *dbs, int size, unsigned int crc)
+{
+       while(size--)
+               crc16_byte(&crc, *(dbs++));
+       return crc;
+}
+
+static void crc8_byte(unsigned int *crc, unsigned char db)
+{
+       int i,f;
+
+       for(i=0;i<8;i++) {
+               f = (*crc ^ db) & 1;
+               *crc >>= 1;
+               db >>= 1;
+               if(f)
+                       *crc ^= 0x8c;
+       }
+       *crc &= 0xff;
+}
+
+static unsigned int crc8_addr(unsigned long addr)
+{
+       int i;
+       unsigned int crc = 0x00;
+
+       for(i=0;i<8;i++)
+               crc8_byte(&crc, addr>>(i<<3));
+       return crc;
+}
+
+static void
+read_redir_page(struct ioc3_driver_data *idd, unsigned long addr, int page,
+                       unsigned char *redir, unsigned char *data)
+{
+       int loops = 16, i;
+
+       while(redir[page] != 0xFF) {
+               page = redir[page]^0xFF;
+               loops--;
+               if(loops<0) {
+                       printk(KERN_ERR "IOC3: NIC circular redirection\n");
+                       return;
+               }
+       }
+       loops = 3;
+       while(loops>0) {
+               nic_addr(idd, addr);
+               nic_write_byte(idd, 0xF0);
+               nic_write_byte(idd, (page << 5) & 0xE0);
+               nic_write_byte(idd, (page >> 3) & 0x1F);
+               for(i=0;i<0x20;i++)
+                       data[i] = nic_read_byte(idd);
+               if(crc16_area(data, 0x20, 0x0000) == 0x800d)
+                       return;
+               loops--;
+       }
+       printk(KERN_ERR "IOC3: CRC error in data page\n");
+       for(i=0;i<0x20;i++)
+               data[i] = 0x00;
+}
+
+static void
+read_redir_map(struct ioc3_driver_data *idd, unsigned long addr,
+                                        unsigned char *redir)
+{
+       int i,j,loops = 3,crc_ok;
+       unsigned int crc;
+
+       while(loops>0) {
+               crc_ok = 1;
+               nic_addr(idd, addr);
+               nic_write_byte(idd, 0xAA);
+               nic_write_byte(idd, 0x00);
+               nic_write_byte(idd, 0x01);
+               for(i=0;i<64;i+=8) {
+                       for(j=0;j<8;j++)
+                               redir[i+j] = nic_read_byte(idd);
+                       crc = crc16_area(redir+i, 8, (i==0)?0x8707:0x0000);
+                       crc16_byte(&crc, nic_read_byte(idd));
+                       crc16_byte(&crc, nic_read_byte(idd));
+                       if(crc != 0x800d)
+                               crc_ok = 0;
+               }
+               if(crc_ok)
+                       return;
+               loops--;
+       }
+       printk(KERN_ERR "IOC3: CRC error in redirection page\n");
+       for(i=0;i<64;i++)
+               redir[i] = 0xFF;
+}
+
+static void read_nic(struct ioc3_driver_data *idd, unsigned long addr)
+{
+       unsigned char redir[64];
+       unsigned char data[64],part[32];
+       int i,j;
+
+       /* read redirections */
+       read_redir_map(idd, addr, redir);
+       /* read data pages */
+       read_redir_page(idd, addr, 0, redir, data);
+       read_redir_page(idd, addr, 1, redir, data+32);
+       /* assemble the part # */
+       j=0;
+       for(i=0;i<19;i++)
+               if(data[i+11] != ' ')
+                       part[j++] = data[i+11];
+       for(i=0;i<6;i++)
+               if(data[i+32] != ' ')
+                       part[j++] = data[i+32];
+       part[j] = 0;
+       /* skip Octane power supplies */
+       if(!strncmp(part, "060-0035-", 9))
+               return;
+       if(!strncmp(part, "060-0038-", 9))
+               return;
+       strcpy(idd->nic_part, part);
+       /* assemble the serial # */
+       j=0;
+       for(i=0;i<10;i++)
+               if(data[i+1] != ' ')
+                       idd->nic_serial[j++] = data[i+1];
+       idd->nic_serial[j] = 0;
+}
+
+static void read_mac(struct ioc3_driver_data *idd, unsigned long addr)
+{
+       int i, loops = 3;
+       unsigned char data[13];
+
+       while(loops>0) {
+               nic_addr(idd, addr);
+               nic_write_byte(idd, 0xF0);
+               nic_write_byte(idd, 0x00);
+               nic_write_byte(idd, 0x00);
+               nic_read_byte(idd);
+               for(i=0;i<13;i++)
+                       data[i] = nic_read_byte(idd);
+               if(crc16_area(data, 13, 0x0000) == 0x800d) {
+                       for(i=10;i>4;i--)
+                               idd->nic_mac[10-i] = data[i];
+                       return;
+               }
+               loops--;
+       }
+       printk(KERN_ERR "IOC3: CRC error in MAC address\n");
+       for(i=0;i<6;i++)
+               idd->nic_mac[i] = 0x00;
+}
+
+static void probe_nic(struct ioc3_driver_data *idd)
+{
+        int save = 0, loops = 3;
+        unsigned long first, addr;
+
+        idd->vma->gpcr_s = GPCR_MLAN_EN;
+
+        while(loops>0) {
+                idd->nic_part[0] = 0;
+                idd->nic_serial[0] = 0;
+                addr = first = nic_find(idd, &save, 0);
+                if(!first)
+                        return;
+                while(1) {
+                        if(crc8_addr(addr))
+                                break;
+                        else {
+                                switch(addr & 0xFF) {
+                                case 0x0B:
+                                        read_nic(idd, addr);
+                                        break;
+                                case 0x09:
+                                case 0x89:
+                                case 0x91:
+                                        read_mac(idd, addr);
+                                        break;
+                                }
+                        }
+                        addr = nic_find(idd, &save, addr);
+                        if(addr == first)
+                                return;
+                }
+                loops--;
+        }
+        printk(KERN_ERR "IOC3: CRC error in NIC address\n");
+}
+
+/* Interrupts */
+
+static inline void
+write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&idd->ir_lock, flags);
+       switch (which) {
+       case IOC3_W_IES:
+               writel(val, &idd->vma->sio_ies);
+               break;
+       case IOC3_W_IEC:
+               writel(val, &idd->vma->sio_iec);
+               break;
+       }
+       spin_unlock_irqrestore(&idd->ir_lock, flags);
+}
+static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd)
+{
+       unsigned long flag;
+       uint32_t intrs = 0;
+
+       spin_lock_irqsave(&idd->ir_lock, flag);
+       intrs = readl(&idd->vma->sio_ir);
+       intrs &= readl(&idd->vma->sio_ies);
+       spin_unlock_irqrestore(&idd->ir_lock, flag);
+       return intrs;
+}
+
+static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
+{
+       unsigned long flags;
+       struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
+       int handled = 1, id;
+       unsigned int pending;
+
+       read_lock_irqsave(&ioc3_submodules_lock, flags);
+
+       if(idd->dual_irq && idd->vma->eisr) {
+               /* send Ethernet IRQ to the driver */
+               if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
+                                               ioc3_ethernet->intr) {
+                       handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
+                                                       idd, 0, regs);
+               }
+       }
+       pending = get_pending_intrs(idd);       /* look at the IO IRQs */
+
+       for(id=0;id<IOC3_MAX_SUBMODULES;id++) {
+               if(idd->active[id] && ioc3_submodules[id]
+                               && (pending & ioc3_submodules[id]->irq_mask)
+                               && ioc3_submodules[id]->intr) {
+                       write_ireg(idd, ioc3_submodules[id]->irq_mask,
+                                                       IOC3_W_IEC);
+                       if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
+                                  idd, pending & ioc3_submodules[id]->irq_mask,
+                                       regs))
+                               pending &= ~ioc3_submodules[id]->irq_mask;
+                       if (ioc3_submodules[id]->reset_mask)
+                               write_ireg(idd, ioc3_submodules[id]->irq_mask,
+                                                       IOC3_W_IES);
+               }
+       }
+       read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+       if(pending) {
+               printk(KERN_WARNING
+                 "IOC3: Pending IRQs 0x%08x discarded and disabled\n",pending);
+               write_ireg(idd, pending, IOC3_W_IEC);
+               handled = 1;
+       }
+       return handled?IRQ_HANDLED:IRQ_NONE;
+}
+
+static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs)
+{
+       unsigned long flags;
+       struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
+       int handled = 1;
+
+       if(!idd->dual_irq)
+               return IRQ_NONE;
+       read_lock_irqsave(&ioc3_submodules_lock, flags);
+       if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
+                               && ioc3_ethernet->intr)
+               handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0,
+                                                               regs);
+       read_unlock_irqrestore(&ioc3_submodules_lock, flags);
+       return handled?IRQ_HANDLED:IRQ_NONE;
+}
+
+void ioc3_enable(struct ioc3_submodule *is,
+                               struct ioc3_driver_data *idd, unsigned int irqs)
+{
+       write_ireg(idd, irqs & is->irq_mask, IOC3_W_IES);
+}
+
+void ioc3_ack(struct ioc3_submodule *is, struct ioc3_driver_data *idd,
+                               unsigned int irqs)
+{
+       writel(irqs & is->irq_mask, &idd->vma->sio_ir);
+}
+
+void ioc3_disable(struct ioc3_submodule *is,
+                               struct ioc3_driver_data *idd, unsigned int irqs)
+{
+       write_ireg(idd, irqs & is->irq_mask, IOC3_W_IEC);
+}
+
+void ioc3_gpcr_set(struct ioc3_driver_data *idd, unsigned int val)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&idd->gpio_lock, flags);
+       writel(val, &idd->vma->gpcr_s);
+       spin_unlock_irqrestore(&idd->gpio_lock, flags);
+}
+
+/* Keep it simple, stupid! */
+static int find_slot(void **tab, int max)
+{
+       int i;
+       for(i=0;i<max;i++)
+               if(!(tab[i]))
+                       return i;
+       return -1;
+}
+
+/* Register an IOC3 submodule */
+int ioc3_register_submodule(struct ioc3_submodule *is)
+{
+       struct ioc3_driver_data *idd;
+       int alloc_id;
+       unsigned long flags;
+
+       write_lock_irqsave(&ioc3_submodules_lock, flags);
+       alloc_id = find_slot((void **)ioc3_submodules, IOC3_MAX_SUBMODULES);
+       if(alloc_id != -1) {
+               ioc3_submodules[alloc_id] = is;
+               if(is->ethernet) {
+                       if(ioc3_ethernet==NULL)
+                               ioc3_ethernet=is;
+                       else
+                               printk(KERN_WARNING
+                                 "IOC3 Ethernet module already registered!\n");
+               }
+       }
+       write_unlock_irqrestore(&ioc3_submodules_lock, flags);
+
+       if(alloc_id == -1) {
+               printk(KERN_WARNING "Increase IOC3_MAX_SUBMODULES!\n");
+               return -ENOMEM;
+       }
+
+       is->id=alloc_id;
+
+       /* Initialize submodule for each IOC3 */
+       if (!is->probe)
+               return 0;
+
+       down_read(&ioc3_devices_rwsem);
+       list_for_each_entry(idd, &ioc3_devices, list) {
+               /* set to 1 for IRQs in probe */
+               idd->active[alloc_id] = 1;
+               idd->active[alloc_id] = !is->probe(is, idd);
+       }
+       up_read(&ioc3_devices_rwsem);
+
+       return 0;
+}
+
+/* Unregister an IOC3 submodule */
+void ioc3_unregister_submodule(struct ioc3_submodule *is)
+{
+       struct ioc3_driver_data *idd;
+       unsigned long flags;
+
+       write_lock_irqsave(&ioc3_submodules_lock, flags);
+       if(ioc3_submodules[is->id]==is)
+               ioc3_submodules[is->id]=NULL;
+       else
+               printk(KERN_WARNING
+                       "IOC3 submodule %s has wrong ID.\n",is->name);
+       if(ioc3_ethernet==is)
+               ioc3_ethernet = NULL;
+       write_unlock_irqrestore(&ioc3_submodules_lock, flags);
+
+       /* Remove submodule for each IOC3 */
+       down_read(&ioc3_devices_rwsem);
+       list_for_each_entry(idd, &ioc3_devices, list)
+               if(idd->active[is->id]) {
+                       if(is->remove)
+                               if(is->remove(is, idd))
+                                       printk(KERN_WARNING
+                                              "%s: IOC3 submodule %s remove failed "
+                                              "for pci_dev %s.\n",
+                                              __FUNCTION__, module_name(is->owner),
+                                              pci_name(idd->pdev));
+                       idd->active[is->id] = 0;
+                       if(is->irq_mask)
+                               write_ireg(idd, is->irq_mask, IOC3_W_IEC);
+               }
+       up_read(&ioc3_devices_rwsem);
+}
+
+/*********************
+ * Device management *
+ *********************/
+
+static char *
+ioc3_class_names[]={"unknown", "IP27 BaseIO", "IP30 system", "MENET 1/2/3",
+                       "MENET 4", "CADduo", "Altix Serial"};
+
+static int ioc3_class(struct ioc3_driver_data *idd)
+{
+       int res = IOC3_CLASS_NONE;
+       /* NIC-based logic */
+       if(!strncmp(idd->nic_part, "030-0891-", 9))
+               res = IOC3_CLASS_BASE_IP30;
+       if(!strncmp(idd->nic_part, "030-1155-", 9))
+               res = IOC3_CLASS_CADDUO;
+       if(!strncmp(idd->nic_part, "030-1657-", 9))
+               res = IOC3_CLASS_SERIAL;
+       if(!strncmp(idd->nic_part, "030-1664-", 9))
+               res = IOC3_CLASS_SERIAL;
+       /* total random heuristics */
+#ifdef CONFIG_SGI_IP27
+       if(!idd->nic_part[0])
+               res = IOC3_CLASS_BASE_IP27;
+#endif
+       /* print educational message */
+       printk(KERN_INFO "IOC3 part: [%s], serial: [%s] => class %s\n",
+                       idd->nic_part, idd->nic_serial, ioc3_class_names[res]);
+       return res;
+}
+/* Adds a new instance of an IOC3 card */
+static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
+{
+       struct ioc3_driver_data *idd;
+       uint32_t pcmd;
+       int ret, id;
+
+       /* Enable IOC3 and take ownership of it */
+       if ((ret = pci_enable_device(pdev))) {
+               printk(KERN_WARNING
+                      "%s: Failed to enable IOC3 device for pci_dev %s.\n",
+                      __FUNCTION__, pci_name(pdev));
+               goto out;
+       }
+       pci_set_master(pdev);
+
+#ifdef USE_64BIT_DMA
+        ret = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+        if (!ret) {
+                ret = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+                if (ret < 0) {
+                        printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA "
+                               "for consistent allocations\n",
+                               __FUNCTION__);
+                }
+       }
+#endif
+
+       /* Set up per-IOC3 data */
+       idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
+       if (!idd) {
+               printk(KERN_WARNING
+                      "%s: Failed to allocate IOC3 data for pci_dev %s.\n",
+                      __FUNCTION__, pci_name(pdev));
+               ret = -ENODEV;
+               goto out_idd;
+       }
+       memset(idd, 0, sizeof(struct ioc3_driver_data));
+       spin_lock_init(&idd->ir_lock);
+       spin_lock_init(&idd->gpio_lock);
+       idd->pdev = pdev;
+
+       /* Map all IOC3 registers.  These are shared between subdevices
+        * so the main IOC3 module manages them.
+        */
+       idd->pma = pci_resource_start(pdev, 0);
+       if (!idd->pma) {
+               printk(KERN_WARNING
+                      "%s: Unable to find IOC3 resource "
+                      "for pci_dev %s.\n",
+                      __FUNCTION__, pci_name(pdev));
+               ret = -ENODEV;
+               goto out_pci;
+       }
+       if (!request_region(idd->pma, IOC3_PCI_SIZE, "ioc3")) {
+               printk(KERN_WARNING
+                      "%s: Unable to request IOC3 region "
+                      "for pci_dev %s.\n",
+                      __FUNCTION__, pci_name(pdev));
+               ret = -ENODEV;
+               goto out_pci;
+       }
+       idd->vma = ioremap(idd->pma, IOC3_PCI_SIZE);
+       if (!idd->vma) {
+               printk(KERN_WARNING
+                      "%s: Unable to remap IOC3 region "
+                      "for pci_dev %s.\n",
+                      __FUNCTION__, pci_name(pdev));
+               ret = -ENODEV;
+               goto out_misc_region;
+       }
+
+       /* Track PCI-device specific data */
+       pci_set_drvdata(pdev, idd);
+       down_write(&ioc3_devices_rwsem);
+       list_add(&idd->list, &ioc3_devices);
+       idd->id = ioc3_counter++;
+       up_write(&ioc3_devices_rwsem);
+
+       idd->gpdr_shadow = idd->vma->gpdr;
+
+       /* Read IOC3 NIC contents */
+       probe_nic(idd);
+
+       /* Detect IOC3 class */
+       idd->class = ioc3_class(idd);
+
+       /* Initialize IOC3 */
+       pci_read_config_dword(pdev, PCI_COMMAND, &pcmd);
+       pci_write_config_dword(pdev, PCI_COMMAND,
+                               pcmd | PCI_COMMAND_MEMORY |
+                               PCI_COMMAND_PARITY | PCI_COMMAND_SERR |
+                               PCI_SCR_DROP_MODE_EN);
+
+       write_ireg(idd, ~0, IOC3_W_IEC);
+       writel(~0, &idd->vma->sio_ir);
+
+       /* Set up IRQs */
+       if(idd->class == IOC3_CLASS_BASE_IP30
+                               || idd->class == IOC3_CLASS_BASE_IP27) {
+               writel(0, &idd->vma->eier);
+               writel(~0, &idd->vma->eisr);
+
+               idd->dual_irq = 1;
+               if (!request_irq(pdev->irq, ioc3_intr_eth, SA_SHIRQ,
+                                "ioc3-eth", (void *)idd)) {
+                       idd->irq_eth = pdev->irq;
+               } else {
+                       printk(KERN_WARNING
+                              "%s : request_irq fails for IRQ 0x%x\n ",
+                              __FUNCTION__, pdev->irq);
+               }
+               if (!request_irq(pdev->irq+2, ioc3_intr_io, SA_SHIRQ,
+                                "ioc3-io", (void *)idd)) {
+                       idd->irq_io = pdev->irq+2;
+               } else {
+                       printk(KERN_WARNING
+                              "%s : request_irq fails for IRQ 0x%x\n ",
+                              __FUNCTION__, pdev->irq+2);
+               }
+       } else {
+               if (!request_irq(pdev->irq, ioc3_intr_io, SA_SHIRQ,
+                                "ioc3", (void *)idd)) {
+                       idd->irq_io = pdev->irq;
+               } else {
+                       printk(KERN_WARNING
+                              "%s : request_irq fails for IRQ 0x%x\n ",
+                              __FUNCTION__, pdev->irq);
+               }
+       }
+
+       /* Add this IOC3 to all submodules */
+       read_lock(&ioc3_submodules_lock);
+       for(id=0;id<IOC3_MAX_SUBMODULES;id++)
+               if(ioc3_submodules[id] && ioc3_submodules[id]->probe) {
+                       idd->active[id] = 1;
+                       idd->active[id] = !ioc3_submodules[id]->probe
+                                               (ioc3_submodules[id], idd);
+               }
+       read_unlock(&ioc3_submodules_lock);
+
+       printk(KERN_INFO "IOC3 Master Driver loaded for %s\n", pci_name(pdev));
+
+       return 0;
+
+out_misc_region:
+       release_region(idd->pma, IOC3_PCI_SIZE);
+out_pci:
+       kfree(idd);
+out_idd:
+       pci_disable_device(pdev);
+out:
+       return ret;
+}
+
+/* Removes a particular instance of an IOC3 card. */
+static void ioc3_remove(struct pci_dev *pdev)
+{
+       int id;
+       struct ioc3_driver_data *idd;
+
+       idd = pci_get_drvdata(pdev);
+
+       /* Remove this IOC3 from all submodules */
+       read_lock(&ioc3_submodules_lock);
+       for(id=0;id<IOC3_MAX_SUBMODULES;id++)
+               if(idd->active[id]) {
+                       if(ioc3_submodules[id] && ioc3_submodules[id]->remove)
+                               if(ioc3_submodules[id]->remove(ioc3_submodules[id],
+                                                               idd))
+                                       printk(KERN_WARNING
+                                              "%s: IOC3 submodule 0x%s remove failed "
+                                              "for pci_dev %s.\n",
+                                               __FUNCTION__,
+                                               module_name(ioc3_submodules[id]->owner),
+                                               pci_name(pdev));
+                       idd->active[id] = 0;
+               }
+       read_unlock(&ioc3_submodules_lock);
+
+       /* Clear and disable all IRQs */
+       write_ireg(idd, ~0, IOC3_W_IEC);
+       writel(~0, &idd->vma->sio_ir);
+
+       /* Release resources */
+       free_irq(idd->irq_io, (void *)idd);
+       if(idd->dual_irq)
+               free_irq(idd->irq_eth, (void *)idd);
+       iounmap(idd->vma);
+       release_region(idd->pma, IOC3_PCI_SIZE);
+
+       /* Disable IOC3 and relinquish */
+       pci_disable_device(pdev);
+
+       /* Remove and free driver data */
+       down_write(&ioc3_devices_rwsem);
+       list_del(&idd->list);
+       up_write(&ioc3_devices_rwsem);
+       kfree(idd);
+}
+
+static struct pci_device_id ioc3_id_table[] = {
+       {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID},
+       {0}
+};
+
+static struct pci_driver ioc3_driver = {
+       .name = "IOC3",
+       .id_table = ioc3_id_table,
+       .probe = ioc3_probe,
+       .remove = ioc3_remove,
+};
+
+MODULE_DEVICE_TABLE(pci, ioc3_id_table);
+
+/*********************
+ * Module management *
+ *********************/
+
+/* Module load */
+static int __devinit ioc3_init(void)
+{
+       if (ia64_platform_is("sn2"))
+               return pci_register_driver(&ioc3_driver);
+       return 0;
+}
+
+/* Module unload */
+static void __devexit ioc3_exit(void)
+{
+       pci_unregister_driver(&ioc3_driver);
+}
+
+module_init(ioc3_init);
+module_exit(ioc3_exit);
+
+MODULE_AUTHOR("Stanislaw Skowronek <skylark@linux-mips.org>");
+MODULE_DESCRIPTION("PCI driver for SGI IOC3");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ioc3_register_submodule);
+EXPORT_SYMBOL(ioc3_unregister_submodule);
+EXPORT_SYMBOL(ioc3_ack);
+EXPORT_SYMBOL(ioc3_gpcr_set);
+EXPORT_SYMBOL(ioc3_disable);
+EXPORT_SYMBOL(ioc3_enable);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
new file mode 100644 (file)
index 0000000..b77dbd6
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# SPI driver configuration
+#
+# NOTE:  the reason this doesn't show SPI slave support is mostly that
+# nobody's needed a slave side API yet.  The master-role API is not
+# fully appropriate there, so it'd need some thought to do well.
+#
+menu "SPI support"
+
+config SPI
+       bool "SPI support"
+       help
+         The "Serial Peripheral Interface" is a low level synchronous
+         protocol.  Chips that support SPI can have data transfer rates
+         up to several tens of Mbit/sec.  Chips are addressed with a
+         controller and a chipselect.  Most SPI slaves don't support
+         dynamic device discovery; some are even write-only or read-only.
+
+         SPI is widely used by microcontollers to talk with sensors,
+         eeprom and flash memory, codecs and various other controller
+         chips, analog to digital (and d-to-a) converters, and more.
+         MMC and SD cards can be accessed using SPI protocol; and for
+         DataFlash cards used in MMC sockets, SPI must always be used.
+
+         SPI is one of a family of similar protocols using a four wire
+         interface (select, clock, data in, data out) including Microwire
+         (half duplex), SSP, SSI, and PSP.  This driver framework should
+         work with most such devices and controllers.
+
+config SPI_DEBUG
+       boolean "Debug support for SPI drivers"
+       depends on SPI && DEBUG_KERNEL
+       help
+         Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
+         sysfs, and debugfs support in SPI controller and protocol drivers.
+
+#
+# MASTER side ... talking to discrete SPI slave chips including microcontrollers
+#
+
+config SPI_MASTER
+#      boolean "SPI Master Support"
+       boolean
+       default SPI
+       help
+         If your system has an master-capable SPI controller (which
+         provides the clock and chipselect), you can enable that
+         controller and the protocol drivers for the SPI slave chips
+         that are connected.
+
+comment "SPI Master Controller Drivers"
+       depends on SPI_MASTER
+
+config SPI_BITBANG
+       tristate "Bitbanging SPI master"
+       depends on SPI_MASTER && EXPERIMENTAL
+       help
+         With a few GPIO pins, your system can bitbang the SPI protocol.
+         Select this to get SPI support through I/O pins (GPIO, parallel
+         port, etc).  Or, some systems' SPI master controller drivers use
+         this code to manage the per-word or per-transfer accesses to the
+         hardware shift registers.
+
+         This is library code, and is automatically selected by drivers that
+         need it.  You only need to select this explicitly to support driver
+         modules that aren't part of this kernel tree.
+
+config SPI_BUTTERFLY
+       tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+       depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+       select SPI_BITBANG
+       help
+         This uses a custom parallel port cable to connect to an AVR
+         Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+         inexpensive battery powered microcontroller evaluation board.
+         This same cable can be used to flash new firmware.
+
+config SPI_BUTTERFLY
+       tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+       depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+       select SPI_BITBANG
+       help
+         This uses a custom parallel port cable to connect to an AVR
+         Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+         inexpensive battery powered microcontroller evaluation board.
+         This same cable can be used to flash new firmware.
+
+#
+# Add new SPI master controllers in alphabetical order above this line
+#
+
+
+#
+# There are lots of SPI device types, with sensors and memory
+# being probably the most widely used ones.
+#
+comment "SPI Protocol Masters"
+       depends on SPI_MASTER
+
+
+#
+# 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
new file mode 100644 (file)
index 0000000..c2c87e8
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# Makefile for kernel SPI drivers.
+#
+
+ifeq ($(CONFIG_SPI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+# small core, mostly translating board-specific
+# config declarations into driver model code
+obj-$(CONFIG_SPI_MASTER)               += spi.o
+
+# SPI master controller drivers (bus)
+obj-$(CONFIG_SPI_BITBANG)              += spi_bitbang.o
+obj-$(CONFIG_SPI_BUTTERFLY)            += spi_butterfly.o
+#      ... add above this line ...
+
+# SPI protocol drivers (device/link on bus)
+#      ... add above this line ...
+
+# SPI slave controller drivers (upstream link)
+#      ... add above this line ...
+
+# SPI slave drivers (protocol for that link)
+#      ... add above this line ...
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
new file mode 100644 (file)
index 0000000..791c4dc
--- /dev/null
@@ -0,0 +1,642 @@
+/*
+ * spi.c - SPI init/core code
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/spi/spi.h>
+
+
+/* SPI bustype and spi_master class are registered after board init code
+ * provides the SPI device tables, ensuring that both are present by the
+ * time controller driver registration causes spi_devices to "enumerate".
+ */
+static void spidev_release(struct device *dev)
+{
+       const struct spi_device *spi = to_spi_device(dev);
+
+       /* spi masters may cleanup for released devices */
+       if (spi->master->cleanup)
+               spi->master->cleanup(spi);
+
+       spi_master_put(spi->master);
+       kfree(dev);
+}
+
+static ssize_t
+modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+{
+       const struct spi_device *spi = to_spi_device(dev);
+
+       return snprintf(buf, BUS_ID_SIZE + 1, "%s\n", spi->modalias);
+}
+
+static struct device_attribute spi_dev_attrs[] = {
+       __ATTR_RO(modalias),
+       __ATTR_NULL,
+};
+
+/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
+ * and the sysfs version makes coldplug work too.
+ */
+
+static int spi_match_device(struct device *dev, struct device_driver *drv)
+{
+       const struct spi_device *spi = to_spi_device(dev);
+
+       return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
+}
+
+static int spi_uevent(struct device *dev, char **envp, int num_envp,
+               char *buffer, int buffer_size)
+{
+       const struct spi_device         *spi = to_spi_device(dev);
+
+       envp[0] = buffer;
+       snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
+       envp[1] = NULL;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * NOTE:  the suspend() method for an spi_master controller driver
+ * should verify that all its child devices are marked as suspended;
+ * suspend requests delivered through sysfs power/state files don't
+ * enforce such constraints.
+ */
+static int spi_suspend(struct device *dev, pm_message_t message)
+{
+       int                     value;
+       struct spi_driver       *drv = to_spi_driver(dev->driver);
+
+       if (!drv->suspend)
+               return 0;
+
+       /* suspend will stop irqs and dma; no more i/o */
+       value = drv->suspend(to_spi_device(dev), message);
+       if (value == 0)
+               dev->power.power_state = message;
+       return value;
+}
+
+static int spi_resume(struct device *dev)
+{
+       int                     value;
+       struct spi_driver       *drv = to_spi_driver(dev->driver);
+
+       if (!drv->resume)
+               return 0;
+
+       /* resume may restart the i/o queue */
+       value = drv->resume(to_spi_device(dev));
+       if (value == 0)
+               dev->power.power_state = PMSG_ON;
+       return value;
+}
+
+#else
+#define spi_suspend    NULL
+#define spi_resume     NULL
+#endif
+
+struct bus_type spi_bus_type = {
+       .name           = "spi",
+       .dev_attrs      = spi_dev_attrs,
+       .match          = spi_match_device,
+       .uevent         = spi_uevent,
+       .suspend        = spi_suspend,
+       .resume         = spi_resume,
+};
+EXPORT_SYMBOL_GPL(spi_bus_type);
+
+
+static int spi_drv_probe(struct device *dev)
+{
+       const struct spi_driver         *sdrv = to_spi_driver(dev->driver);
+
+       return sdrv->probe(to_spi_device(dev));
+}
+
+static int spi_drv_remove(struct device *dev)
+{
+       const struct spi_driver         *sdrv = to_spi_driver(dev->driver);
+
+       return sdrv->remove(to_spi_device(dev));
+}
+
+static void spi_drv_shutdown(struct device *dev)
+{
+       const struct spi_driver         *sdrv = to_spi_driver(dev->driver);
+
+       sdrv->shutdown(to_spi_device(dev));
+}
+
+int spi_register_driver(struct spi_driver *sdrv)
+{
+       sdrv->driver.bus = &spi_bus_type;
+       if (sdrv->probe)
+               sdrv->driver.probe = spi_drv_probe;
+       if (sdrv->remove)
+               sdrv->driver.remove = spi_drv_remove;
+       if (sdrv->shutdown)
+               sdrv->driver.shutdown = spi_drv_shutdown;
+       return driver_register(&sdrv->driver);
+}
+EXPORT_SYMBOL_GPL(spi_register_driver);
+
+/*-------------------------------------------------------------------------*/
+
+/* SPI devices should normally not be created by SPI device drivers; that
+ * would make them board-specific.  Similarly with SPI master drivers.
+ * Device registration normally goes into like arch/.../mach.../board-YYY.c
+ * with other readonly (flashable) information about mainboard devices.
+ */
+
+struct boardinfo {
+       struct list_head        list;
+       unsigned                n_board_info;
+       struct spi_board_info   board_info[0];
+};
+
+static LIST_HEAD(board_list);
+static DECLARE_MUTEX(board_lock);
+
+
+/* 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
+ * driver could add devices (which it would learn about out-of-band).
+ */
+struct spi_device *__init_or_module
+spi_new_device(struct spi_master *master, struct spi_board_info *chip)
+{
+       struct spi_device       *proxy;
+       struct device           *dev = master->cdev.dev;
+       int                     status;
+
+       /* NOTE:  caller did any chip->bus_num checks necessary */
+
+       if (!spi_master_get(master))
+               return NULL;
+
+       proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
+       if (!proxy) {
+               dev_err(dev, "can't alloc dev for cs%d\n",
+                       chip->chip_select);
+               goto fail;
+       }
+       proxy->master = master;
+       proxy->chip_select = chip->chip_select;
+       proxy->max_speed_hz = chip->max_speed_hz;
+       proxy->irq = chip->irq;
+       proxy->modalias = chip->modalias;
+
+       snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
+                       "%s.%u", master->cdev.class_id,
+                       chip->chip_select);
+       proxy->dev.parent = dev;
+       proxy->dev.bus = &spi_bus_type;
+       proxy->dev.platform_data = (void *) chip->platform_data;
+       proxy->controller_data = chip->controller_data;
+       proxy->controller_state = NULL;
+       proxy->dev.release = spidev_release;
+
+       /* drivers may modify this default i/o setup */
+       status = master->setup(proxy);
+       if (status < 0) {
+               dev_dbg(dev, "can't %s %s, status %d\n",
+                               "setup", proxy->dev.bus_id, status);
+               goto fail;
+       }
+
+       /* driver core catches callers that misbehave by defining
+        * devices that already exist.
+        */
+       status = device_register(&proxy->dev);
+       if (status < 0) {
+               dev_dbg(dev, "can't %s %s, status %d\n",
+                               "add", proxy->dev.bus_id, status);
+               goto fail;
+       }
+       dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
+       return proxy;
+
+fail:
+       spi_master_put(master);
+       kfree(proxy);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_new_device);
+
+/*
+ * 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
+ * this table of devices forever, so that reloading a controller driver will
+ * not make Linux forget about these hard-wired devices.
+ *
+ * Other code can also call this, e.g. a particular add-on board might provide
+ * SPI devices through its expansion connector, so code initializing that board
+ * would naturally declare its SPI devices.
+ *
+ * The board info passed can safely be __initdata ... but be careful of
+ * any embedded pointers (platform_data, etc), they're copied as-is.
+ */
+int __init
+spi_register_board_info(struct spi_board_info const *info, unsigned n)
+{
+       struct boardinfo        *bi;
+
+       bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+       if (!bi)
+               return -ENOMEM;
+       bi->n_board_info = n;
+       memcpy(bi->board_info, info, n * sizeof *info);
+
+       down(&board_lock);
+       list_add_tail(&bi->list, &board_list);
+       up(&board_lock);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spi_register_board_info);
+
+/* FIXME someone should add support for a __setup("spi", ...) that
+ * creates board info from kernel command lines
+ */
+
+static void __init_or_module
+scan_boardinfo(struct spi_master *master)
+{
+       struct boardinfo        *bi;
+       struct device           *dev = master->cdev.dev;
+
+       down(&board_lock);
+       list_for_each_entry(bi, &board_list, list) {
+               struct spi_board_info   *chip = bi->board_info;
+               unsigned                n;
+
+               for (n = bi->n_board_info; n > 0; n--, chip++) {
+                       if (chip->bus_num != master->bus_num)
+                               continue;
+                       /* some controllers only have one chip, so they
+                        * might not use chipselects.  otherwise, the
+                        * chipselects are numbered 0..max.
+                        */
+                       if (chip->chip_select >= master->num_chipselect
+                                       && master->num_chipselect) {
+                               dev_dbg(dev, "cs%d > max %d\n",
+                                       chip->chip_select,
+                                       master->num_chipselect);
+                               continue;
+                       }
+                       (void) spi_new_device(master, chip);
+               }
+       }
+       up(&board_lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void spi_master_release(struct class_device *cdev)
+{
+       struct spi_master *master;
+
+       master = container_of(cdev, struct spi_master, cdev);
+       kfree(master);
+}
+
+static struct class spi_master_class = {
+       .name           = "spi_master",
+       .owner          = THIS_MODULE,
+       .release        = spi_master_release,
+};
+
+
+/**
+ * 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
+ *     memory is in the class_data field of the returned class_device,
+ *     accessible with spi_master_get_devdata().
+ *
+ * This call is used only by SPI master controller drivers, which are the
+ * only ones directly touching chip registers.  It's how they allocate
+ * an spi_master structure, prior to calling spi_add_master().
+ *
+ * This must be called from context that can sleep.  It returns the SPI
+ * master structure on success, else NULL.
+ *
+ * The caller is responsible for assigning the bus number and initializing
+ * the master's methods before calling spi_add_master(); and (after errors
+ * adding the device) calling spi_master_put() to prevent a memory leak.
+ */
+struct spi_master * __init_or_module
+spi_alloc_master(struct device *dev, unsigned size)
+{
+       struct spi_master       *master;
+
+       if (!dev)
+               return NULL;
+
+       master = kzalloc(size + sizeof *master, SLAB_KERNEL);
+       if (!master)
+               return NULL;
+
+       class_device_initialize(&master->cdev);
+       master->cdev.class = &spi_master_class;
+       master->cdev.dev = get_device(dev);
+       spi_master_set_devdata(master, &master[1]);
+
+       return master;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_master);
+
+/**
+ * spi_register_master - register SPI master controller
+ * @master: initialized master, originally from spi_alloc_master()
+ *
+ * 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
+ * includes calling spi_register_master() to hook up to this SPI bus glue.
+ *
+ * SPI controllers use board specific (often SOC specific) bus numbers,
+ * and board-specific addressing for SPI devices combines those numbers
+ * with chip select numbers.  Since SPI does not directly support dynamic
+ * device identification, boards need configuration tables telling which
+ * chip is at which address.
+ *
+ * This must be called from context that can sleep.  It returns zero on
+ * success, else a negative error code (dropping the master's refcount).
+ * After a successful return, the caller is responsible for calling
+ * spi_unregister_master().
+ */
+int __init_or_module
+spi_register_master(struct spi_master *master)
+{
+       static atomic_t         dyn_bus_id = ATOMIC_INIT(0);
+       struct device           *dev = master->cdev.dev;
+       int                     status = -ENODEV;
+       int                     dynamic = 0;
+
+       if (!dev)
+               return -ENODEV;
+
+       /* convention:  dynamically assigned bus IDs count down from the max */
+       if (master->bus_num == 0) {
+               master->bus_num = atomic_dec_return(&dyn_bus_id);
+               dynamic = 1;
+       }
+
+       /* register the device, then userspace will see it.
+        * registration fails if the bus ID is in use.
+        */
+       snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
+               "spi%u", master->bus_num);
+       status = class_device_add(&master->cdev);
+       if (status < 0)
+               goto done;
+       dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
+                       dynamic ? " (dynamic)" : "");
+
+       /* populate children from any spi device tables */
+       scan_boardinfo(master);
+       status = 0;
+done:
+       return status;
+}
+EXPORT_SYMBOL_GPL(spi_register_master);
+
+
+static int __unregister(struct device *dev, void *unused)
+{
+       /* note: before about 2.6.14-rc1 this would corrupt memory: */
+       spi_unregister_device(to_spi_device(dev));
+       return 0;
+}
+
+/**
+ * spi_unregister_master - unregister SPI master controller
+ * @master: the master being unregistered
+ *
+ * This call is used only by SPI master controller drivers, which are the
+ * only ones directly touching chip registers.
+ *
+ * This must be called from context that can sleep.
+ */
+void spi_unregister_master(struct spi_master *master)
+{
+       (void) device_for_each_child(master->cdev.dev, NULL, __unregister);
+       class_device_unregister(&master->cdev);
+       master->cdev.dev = NULL;
+}
+EXPORT_SYMBOL_GPL(spi_unregister_master);
+
+/**
+ * spi_busnum_to_master - look up master associated with bus_num
+ * @bus_num: the master's bus number
+ *
+ * This call may be used with devices that are registered after
+ * arch init time.  It returns a refcounted pointer to the relevant
+ * spi_master (which the caller must release), or NULL if there is
+ * no such master registered.
+ */
+struct spi_master *spi_busnum_to_master(u16 bus_num)
+{
+       if (bus_num) {
+               char                    name[8];
+               struct kobject          *bus;
+
+               snprintf(name, sizeof name, "spi%u", bus_num);
+               bus = kset_find_obj(&spi_master_class.subsys.kset, name);
+               if (bus)
+                       return container_of(bus, struct spi_master, cdev.kobj);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_busnum_to_master);
+
+
+/*-------------------------------------------------------------------------*/
+
+static void spi_complete(void *arg)
+{
+       complete(arg);
+}
+
+/**
+ * spi_sync - blocking/synchronous SPI data transfers
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers
+ *
+ * This call may only be used from a context that may sleep.  The sleep
+ * is non-interruptible, and has no timeout.  Low-overhead controller
+ * drivers may DMA directly into and out of the message buffers.
+ *
+ * Note that the SPI device's chip select is active during the message,
+ * and then is normally disabled between messages.  Drivers for some
+ * frequently-used devices may want to minimize costs of selecting a chip,
+ * by leaving it selected in anticipation that the next message will go
+ * to the same chip.  (That may increase power usage.)
+ *
+ * Also, the caller is guaranteeing that the memory associated with the
+ * message will not be freed before this call returns.
+ *
+ * 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
+ * or a negative error code from the controller driver.
+ */
+int spi_sync(struct spi_device *spi, struct spi_message *message)
+{
+       DECLARE_COMPLETION(done);
+       int status;
+
+       message->complete = spi_complete;
+       message->context = &done;
+       status = spi_async(spi, message);
+       if (status == 0)
+               wait_for_completion(&done);
+       message->context = NULL;
+       return status;
+}
+EXPORT_SYMBOL_GPL(spi_sync);
+
+#define        SPI_BUFSIZ      (SMP_CACHE_BYTES)
+
+static u8      *buf;
+
+/**
+ * spi_write_then_read - SPI synchronous write followed by read
+ * @spi: device with which data will be exchanged
+ * @txbuf: data to be written (need not be dma-safe)
+ * @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)
+ *
+ * This performs a half duplex MicroWire style transaction with the
+ * device, sending txbuf and then reading rxbuf.  The return value
+ * is zero for success, else a negative errno status code.
+ * 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
+ * spi_{async,sync}() calls with dma-safe buffers.
+ */
+int spi_write_then_read(struct spi_device *spi,
+               const u8 *txbuf, unsigned n_tx,
+               u8 *rxbuf, unsigned n_rx)
+{
+       static DECLARE_MUTEX(lock);
+
+       int                     status;
+       struct spi_message      message;
+       struct spi_transfer     x[2];
+       u8                      *local_buf;
+
+       /* Use preallocated DMA-safe buffer.  We can't avoid copying here,
+        * (as a pure convenience thing), but we can keep heap costs
+        * out of the hot path ...
+        */
+       if ((n_tx + n_rx) > SPI_BUFSIZ)
+               return -EINVAL;
+
+       spi_message_init(&message);
+       memset(x, 0, sizeof x);
+       if (n_tx) {
+               x[0].len = n_tx;
+               spi_message_add_tail(&x[0], &message);
+       }
+       if (n_rx) {
+               x[1].len = n_rx;
+               spi_message_add_tail(&x[1], &message);
+       }
+
+       /* ... unless someone else is using the pre-allocated buffer */
+       if (down_trylock(&lock)) {
+               local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
+               if (!local_buf)
+                       return -ENOMEM;
+       } else
+               local_buf = buf;
+
+       memcpy(local_buf, txbuf, n_tx);
+       x[0].tx_buf = local_buf;
+       x[1].rx_buf = local_buf + n_tx;
+
+       /* do the i/o */
+       status = spi_sync(spi, &message);
+       if (status == 0) {
+               memcpy(rxbuf, x[1].rx_buf, n_rx);
+               status = message.status;
+       }
+
+       if (x[0].tx_buf == buf)
+               up(&lock);
+       else
+               kfree(local_buf);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(spi_write_then_read);
+
+/*-------------------------------------------------------------------------*/
+
+static int __init spi_init(void)
+{
+       int     status;
+
+       buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
+       if (!buf) {
+               status = -ENOMEM;
+               goto err0;
+       }
+
+       status = bus_register(&spi_bus_type);
+       if (status < 0)
+               goto err1;
+
+       status = class_register(&spi_master_class);
+       if (status < 0)
+               goto err2;
+       return 0;
+
+err2:
+       bus_unregister(&spi_bus_type);
+err1:
+       kfree(buf);
+       buf = NULL;
+err0:
+       return status;
+}
+
+/* board_info is normally registered in arch_initcall(),
+ * but even essential drivers wait till later
+ *
+ * REVISIT only boardinfo really needs static linking. the rest (device and
+ * driver registration) _could_ be dynamically linked (modular) ... costs
+ * include needing to have boardinfo data structures be much more public.
+ */
+subsys_initcall(spi_init);
+
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
new file mode 100644 (file)
index 0000000..f037e55
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * spi_bitbang.c - polling/bitbanging SPI master controller driver utilities
+ *
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * FIRST PART (OPTIONAL):  word-at-a-time spi_transfer support.
+ * Use this for GPIO or shift-register level hardware APIs.
+ *
+ * spi_bitbang_cs is in spi_device->controller_state, which is unavailable
+ * to glue code.  These bitbang setup() and cleanup() routines are always
+ * used, though maybe they're called from controller-aware code.
+ *
+ * chipselect() and friends may use use spi_device->controller_data and
+ * controller registers as appropriate.
+ *
+ *
+ * NOTE:  SPI controller pins can often be used as GPIO pins instead,
+ * which means you could use a bitbang driver either to get hardware
+ * working quickly, or testing for differences that aren't speed related.
+ */
+
+struct spi_bitbang_cs {
+       unsigned        nsecs;  /* (clock cycle time)/2 */
+       u32             (*txrx_word)(struct spi_device *spi, unsigned nsecs,
+                                       u32 word, u8 bits);
+       unsigned        (*txrx_bufs)(struct spi_device *,
+                                       u32 (*txrx_word)(
+                                               struct spi_device *spi,
+                                               unsigned nsecs,
+                                               u32 word, u8 bits),
+                                       unsigned, struct spi_transfer *);
+};
+
+static unsigned bitbang_txrx_8(
+       struct spi_device       *spi,
+       u32                     (*txrx_word)(struct spi_device *spi,
+                                       unsigned nsecs,
+                                       u32 word, u8 bits),
+       unsigned                ns,
+       struct spi_transfer     *t
+) {
+       unsigned                bits = spi->bits_per_word;
+       unsigned                count = t->len;
+       const u8                *tx = t->tx_buf;
+       u8                      *rx = t->rx_buf;
+
+       while (likely(count > 0)) {
+               u8              word = 0;
+
+               if (tx)
+                       word = *tx++;
+               word = txrx_word(spi, ns, word, bits);
+               if (rx)
+                       *rx++ = word;
+               count -= 1;
+       }
+       return t->len - count;
+}
+
+static unsigned bitbang_txrx_16(
+       struct spi_device       *spi,
+       u32                     (*txrx_word)(struct spi_device *spi,
+                                       unsigned nsecs,
+                                       u32 word, u8 bits),
+       unsigned                ns,
+       struct spi_transfer     *t
+) {
+       unsigned                bits = spi->bits_per_word;
+       unsigned                count = t->len;
+       const u16               *tx = t->tx_buf;
+       u16                     *rx = t->rx_buf;
+
+       while (likely(count > 1)) {
+               u16             word = 0;
+
+               if (tx)
+                       word = *tx++;
+               word = txrx_word(spi, ns, word, bits);
+               if (rx)
+                       *rx++ = word;
+               count -= 2;
+       }
+       return t->len - count;
+}
+
+static unsigned bitbang_txrx_32(
+       struct spi_device       *spi,
+       u32                     (*txrx_word)(struct spi_device *spi,
+                                       unsigned nsecs,
+                                       u32 word, u8 bits),
+       unsigned                ns,
+       struct spi_transfer     *t
+) {
+       unsigned                bits = spi->bits_per_word;
+       unsigned                count = t->len;
+       const u32               *tx = t->tx_buf;
+       u32                     *rx = t->rx_buf;
+
+       while (likely(count > 3)) {
+               u32             word = 0;
+
+               if (tx)
+                       word = *tx++;
+               word = txrx_word(spi, ns, word, bits);
+               if (rx)
+                       *rx++ = word;
+               count -= 4;
+       }
+       return t->len - count;
+}
+
+/**
+ * spi_bitbang_setup - default setup for per-word I/O loops
+ */
+int spi_bitbang_setup(struct spi_device *spi)
+{
+       struct spi_bitbang_cs   *cs = spi->controller_state;
+       struct spi_bitbang      *bitbang;
+
+       if (!spi->max_speed_hz)
+               return -EINVAL;
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, SLAB_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+       bitbang = spi_master_get_devdata(spi->master);
+
+       if (!spi->bits_per_word)
+               spi->bits_per_word = 8;
+
+       /* spi_transfer level calls that work per-word */
+       if (spi->bits_per_word <= 8)
+               cs->txrx_bufs = bitbang_txrx_8;
+       else if (spi->bits_per_word <= 16)
+               cs->txrx_bufs = bitbang_txrx_16;
+       else if (spi->bits_per_word <= 32)
+               cs->txrx_bufs = bitbang_txrx_32;
+       else
+               return -EINVAL;
+
+       /* per-word shift register access, in hardware or bitbanging */
+       cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
+       if (!cs->txrx_word)
+               return -EINVAL;
+
+       /* nsecs = (clock period)/2 */
+       cs->nsecs = (1000000000/2) / (spi->max_speed_hz);
+       if (cs->nsecs > MAX_UDELAY_MS * 1000)
+               return -EINVAL;
+
+       dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
+                       __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
+                       spi->bits_per_word, 2 * cs->nsecs);
+
+       /* NOTE we _need_ to call chipselect() early, ideally with adapter
+        * setup, unless the hardware defaults cooperate to avoid confusion
+        * between normal (active low) and inverted chipselects.
+        */
+
+       /* deselect chip (low or high) */
+       spin_lock(&bitbang->lock);
+       if (!bitbang->busy) {
+               bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+               ndelay(cs->nsecs);
+       }
+       spin_unlock(&bitbang->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_setup);
+
+/**
+ * spi_bitbang_cleanup - default cleanup for per-word I/O loops
+ */
+void spi_bitbang_cleanup(const struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
+
+static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct spi_bitbang_cs   *cs = spi->controller_state;
+       unsigned                nsecs = cs->nsecs;
+
+       return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * SECOND PART ... simple transfer queue runner.
+ *
+ * This costs a task context per controller, running the queue by
+ * performing each transfer in sequence.  Smarter hardware can queue
+ * several DMA transfers at once, and process several controller queues
+ * in parallel; this driver doesn't match such hardware very well.
+ *
+ * Drivers can provide word-at-a-time i/o primitives, or provide
+ * transfer-at-a-time ones to leverage dma or fifo hardware.
+ */
+static void bitbang_work(void *_bitbang)
+{
+       struct spi_bitbang      *bitbang = _bitbang;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&bitbang->lock, flags);
+       bitbang->busy = 1;
+       while (!list_empty(&bitbang->queue)) {
+               struct spi_message      *m;
+               struct spi_device       *spi;
+               unsigned                nsecs;
+               struct spi_transfer     *t = NULL;
+               unsigned                tmp;
+               unsigned                cs_change;
+               int                     status;
+
+               m = container_of(bitbang->queue.next, struct spi_message,
+                               queue);
+               list_del_init(&m->queue);
+               spin_unlock_irqrestore(&bitbang->lock, flags);
+
+               /* FIXME this is made-up ... the correct value is known to
+                * word-at-a-time bitbang code, and presumably chipselect()
+                * should enforce these requirements too?
+                */
+               nsecs = 100;
+
+               spi = m->spi;
+               tmp = 0;
+               cs_change = 1;
+               status = 0;
+
+               list_for_each_entry (t, &m->transfers, transfer_list) {
+                       if (bitbang->shutdown) {
+                               status = -ESHUTDOWN;
+                               break;
+                       }
+
+                       /* set up default clock polarity, and activate chip;
+                        * this implicitly updates clock and spi modes as
+                        * previously recorded for this device via setup().
+                        * (and also deselects any other chip that might be
+                        * selected ...)
+                        */
+                       if (cs_change) {
+                               bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+                               ndelay(nsecs);
+                       }
+                       cs_change = t->cs_change;
+                       if (!t->tx_buf && !t->rx_buf && t->len) {
+                               status = -EINVAL;
+                               break;
+                       }
+
+                       /* transfer data.  the lower level code handles any
+                        * new dma mappings it needs. our caller always gave
+                        * us dma-safe buffers.
+                        */
+                       if (t->len) {
+                               /* REVISIT dma API still needs a designated
+                                * DMA_ADDR_INVALID; ~0 might be better.
+                                */
+                               if (!m->is_dma_mapped)
+                                       t->rx_dma = t->tx_dma = 0;
+                               status = bitbang->txrx_bufs(spi, t);
+                       }
+                       if (status != t->len) {
+                               if (status > 0)
+                                       status = -EMSGSIZE;
+                               break;
+                       }
+                       m->actual_length += status;
+                       status = 0;
+
+                       /* protocol tweaks before next transfer */
+                       if (t->delay_usecs)
+                               udelay(t->delay_usecs);
+
+                       if (!cs_change)
+                               continue;
+                       if (t->transfer_list.next == &m->transfers)
+                               break;
+
+                       /* sometimes a short mid-message deselect of the chip
+                        * may be needed to terminate a mode or command
+                        */
+                       ndelay(nsecs);
+                       bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+                       ndelay(nsecs);
+               }
+
+               m->status = status;
+               m->complete(m->context);
+
+               /* normally deactivate chipselect ... unless no error and
+                * cs_change has hinted that the next message will probably
+                * be for this chip too.
+                */
+               if (!(status == 0 && cs_change)) {
+                       ndelay(nsecs);
+                       bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+                       ndelay(nsecs);
+               }
+
+               spin_lock_irqsave(&bitbang->lock, flags);
+       }
+       bitbang->busy = 0;
+       spin_unlock_irqrestore(&bitbang->lock, flags);
+}
+
+/**
+ * spi_bitbang_transfer - default submit to transfer queue
+ */
+int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
+{
+       struct spi_bitbang      *bitbang;
+       unsigned long           flags;
+
+       m->actual_length = 0;
+       m->status = -EINPROGRESS;
+
+       bitbang = spi_master_get_devdata(spi->master);
+       if (bitbang->shutdown)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&bitbang->lock, flags);
+       list_add_tail(&m->queue, &bitbang->queue);
+       queue_work(bitbang->workqueue, &bitbang->work);
+       spin_unlock_irqrestore(&bitbang->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * spi_bitbang_start - start up a polled/bitbanging SPI master driver
+ * @bitbang: driver handle
+ *
+ * Caller should have zero-initialized all parts of the structure, and then
+ * provided callbacks for chip selection and I/O loops.  If the master has
+ * a transfer method, its final step should call spi_bitbang_transfer; or,
+ * that's the default if the transfer routine is not initialized.  It should
+ * also set up the bus number and number of chipselects.
+ *
+ * For i/o loops, provide callbacks either per-word (for bitbanging, or for
+ * hardware that basically exposes a shift register) or per-spi_transfer
+ * (which takes better advantage of hardware like fifos or DMA engines).
+ *
+ * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and
+ * spi_bitbang_cleanup to handle those spi master methods.  Those methods are
+ * the defaults if the bitbang->txrx_bufs routine isn't initialized.
+ *
+ * This routine registers the spi_master, which will process requests in a
+ * dedicated task, keeping IRQs unblocked most of the time.  To stop
+ * processing those requests, call spi_bitbang_stop().
+ */
+int spi_bitbang_start(struct spi_bitbang *bitbang)
+{
+       int     status;
+
+       if (!bitbang->master || !bitbang->chipselect)
+               return -EINVAL;
+
+       INIT_WORK(&bitbang->work, bitbang_work, bitbang);
+       spin_lock_init(&bitbang->lock);
+       INIT_LIST_HEAD(&bitbang->queue);
+
+       if (!bitbang->master->transfer)
+               bitbang->master->transfer = spi_bitbang_transfer;
+       if (!bitbang->txrx_bufs) {
+               bitbang->use_dma = 0;
+               bitbang->txrx_bufs = spi_bitbang_bufs;
+               if (!bitbang->master->setup) {
+                       bitbang->master->setup = spi_bitbang_setup;
+                       bitbang->master->cleanup = spi_bitbang_cleanup;
+               }
+       } else if (!bitbang->master->setup)
+               return -EINVAL;
+
+       /* this task is the only thing to touch the SPI bits */
+       bitbang->busy = 0;
+       bitbang->workqueue = create_singlethread_workqueue(
+                       bitbang->master->cdev.dev->bus_id);
+       if (bitbang->workqueue == NULL) {
+               status = -EBUSY;
+               goto err1;
+       }
+
+       /* driver may get busy before register() returns, especially
+        * if someone registered boardinfo for devices
+        */
+       status = spi_register_master(bitbang->master);
+       if (status < 0)
+               goto err2;
+
+       return status;
+
+err2:
+       destroy_workqueue(bitbang->workqueue);
+err1:
+       return status;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_start);
+
+/**
+ * spi_bitbang_stop - stops the task providing spi communication
+ */
+int spi_bitbang_stop(struct spi_bitbang *bitbang)
+{
+       unsigned        limit = 500;
+
+       spin_lock_irq(&bitbang->lock);
+       bitbang->shutdown = 0;
+       while (!list_empty(&bitbang->queue) && limit--) {
+               spin_unlock_irq(&bitbang->lock);
+
+               dev_dbg(bitbang->master->cdev.dev, "wait for queue\n");
+               msleep(10);
+
+               spin_lock_irq(&bitbang->lock);
+       }
+       spin_unlock_irq(&bitbang->lock);
+       if (!list_empty(&bitbang->queue)) {
+               dev_err(bitbang->master->cdev.dev, "queue didn't empty\n");
+               return -EBUSY;
+       }
+
+       destroy_workqueue(bitbang->workqueue);
+
+       spi_unregister_master(bitbang->master);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_stop);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
new file mode 100644 (file)
index 0000000..79a3c59
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * spi_butterfly.c - parport-to-butterfly adapter
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/parport.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/partitions.h>
+
+
+/*
+ * This uses SPI to talk with an "AVR Butterfly", which is a $US20 card
+ * with a battery powered AVR microcontroller and lots of goodies.  You
+ * can use GCC to develop firmware for this.
+ *
+ * See Documentation/spi/butterfly for information about how to build
+ * 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 */
+
+#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 */
+
+
+
+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 */
+       struct spi_bitbang      bitbang;
+
+       struct parport          *port;
+       struct pardevice        *pd;
+
+       u8                      lastbyte;
+
+       struct spi_device       *dataflash;
+       struct spi_device       *butterfly;
+       struct spi_board_info   info[2];
+
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * 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;
+
+       if (is_on)
+               byte |= bit;
+       else
+               byte &= ~bit;
+       parport_write_data(pp->port, byte);
+       pp->lastbyte = byte;
+}
+
+static inline void
+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;
+
+       if (is_on)
+               byte |= bit;
+       else
+               byte &= ~bit;
+       parport_write_data(pp->port, byte);
+       pp->lastbyte = byte;
+}
+
+static inline int getmiso(struct spi_device *spi)
+{
+       struct butterfly        *pp = spidev_to_pp(spi);
+       int                     value;
+       u8                      bit;
+
+       if (is_usidev(spi))
+               bit = usi_miso_bit;
+       else
+               bit = spi_miso_bit;
+
+       /* only STATUS_BUSY is NOT negated */
+       value = !(parport_read_status(pp->port) & bit);
+       return (bit == PARPORT_STATUS_BUSY) ? value : !value;
+}
+
+static void butterfly_chipselect(struct spi_device *spi, int value)
+{
+       struct butterfly        *pp = spidev_to_pp(spi);
+
+       /* set default clock polarity */
+       if (value)
+               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 */
+       if (spi_cs_bit == PARPORT_CONTROL_INIT)
+               value = !value;
+
+       /* here, value == "bit value to write in control register"  */
+
+       parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
+}
+
+
+/* we only needed to implement one mode here, and choose SPI_MODE_0 */
+
+#define        spidelay(X)     do{}while(0)
+//#define      spidelay        ndelay
+
+#define        EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32
+butterfly_txrx_word_mode0(struct spi_device *spi,
+               unsigned nsecs,
+               u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* override default partitioning with cmdlinepart */
+static struct mtd_partition partitions[] = { {
+       /* JFFS2 wants partitions of 4*N blocks for this device ... */
+
+       /* sector 0 = 8 pages * 264 bytes/page (1 block)
+        * sector 1 = 248 pages * 264 bytes/page
+        */
+       .name           = "bookkeeping",        // 66 KB
+       .offset         = 0,
+       .size           = (8 + 248) * 264,
+//     .mask_flags     = MTD_WRITEABLE,
+}, {
+       /* sector 2 = 256 pages * 264 bytes/page
+        * sectors 3-5 = 512 pages * 264 bytes/page
+        */
+       .name           = "filesystem",         // 462 KB
+       .offset         = MTDPART_OFS_APPEND,
+       .size           = MTDPART_SIZ_FULL,
+} };
+
+static struct flash_platform_data flash = {
+       .name           = "butterflash",
+       .parts          = partitions,
+       .nr_parts       = ARRAY_SIZE(partitions),
+};
+
+
+/* REVISIT remove this ugly global and its "only one" limitation */
+static struct butterfly *butterfly;
+
+static void butterfly_attach(struct parport *p)
+{
+       struct pardevice        *pd;
+       int                     status;
+       struct butterfly        *pp;
+       struct spi_master       *master;
+       struct platform_device  *pdev;
+
+       if (butterfly)
+               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);
+
+       master = spi_alloc_master(&pdev->dev, sizeof *pp);
+       if (!master) {
+               status = -ENOMEM;
+               goto done;
+       }
+       pp = spi_master_get_devdata(master);
+
+       /*
+        * SPI and bitbang hookup
+        *
+        * use default setup(), cleanup(), and transfer() methods; and
+        * only bother implementing mode 0.  Start it later.
+        */
+       master->bus_num = 42;
+       master->num_chipselect = 2;
+
+       pp->bitbang.master = spi_master_get(master);
+       pp->bitbang.chipselect = butterfly_chipselect;
+       pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
+
+       /*
+        * parport hookup
+        */
+       pp->port = p;
+       pd = parport_register_device(p, "spi_butterfly",
+                       NULL, NULL, NULL,
+                       0 /* FLAGS */, pp);
+       if (!pd) {
+               status = -ENOMEM;
+               goto clean0;
+       }
+       pp->pd = pd;
+
+       status = parport_claim(pd);
+       if (status < 0)
+               goto clean1;
+
+       /*
+        * Butterfly reset, powerup, run firmware
+        */
+       pr_debug("%s: powerup/reset Butterfly\n", p->name);
+
+       /* nCS for dataflash (this bit is inverted on output) */
+       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)
+        */
+       pp->lastbyte |= vcc_bits;
+       parport_write_data(pp->port, pp->lastbyte);
+       msleep(5);
+
+       /* take it out of reset; assume long reset delay */
+       pp->lastbyte |= butterfly_nreset;
+       parport_write_data(pp->port, pp->lastbyte);
+       msleep(100);
+
+
+       /*
+        * Start SPI ... for now, hide that we're two physical busses.
+        */
+       status = spi_bitbang_start(&pp->bitbang);
+       if (status < 0)
+               goto clean2;
+
+       /* Bus 1 lets us talk to at45db041b (firmware disables AVR)
+        * or AVR (firmware resets at45, acts as spi slave)
+        */
+       pp->info[0].max_speed_hz = 15 * 1000 * 1000;
+       strcpy(pp->info[0].modalias, "mtd_dataflash");
+       pp->info[0].platform_data = &flash;
+       pp->info[0].chip_select = 1;
+       pp->info[0].controller_data = pp;
+       pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]);
+       if (pp->dataflash)
+               pr_debug("%s: dataflash at %s\n", p->name,
+                               pp->dataflash->dev.bus_id);
+
+#ifdef HAVE_USI
+       /* even more custom 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;
+       return;
+
+clean2:
+       /* turn off VCC */
+       parport_write_data(pp->port, 0);
+
+       parport_release(pp->pd);
+clean1:
+       parport_unregister_device(pd);
+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
+        * the parport to the "struct butterfly" associated with it?
+        * "old school" driver-internal device lists?
+        */
+       if (!butterfly || butterfly->port != p)
+               return;
+       pp = butterfly;
+       butterfly = NULL;
+
+#ifdef HAVE_USI
+       spi_unregister_device(pp->butterfly);
+       pp->butterfly = NULL;
+#endif
+       spi_unregister_device(pp->dataflash);
+       pp->dataflash = NULL;
+
+       status = spi_bitbang_stop(&pp->bitbang);
+
+       /* turn off VCC */
+       parport_write_data(pp->port, 0);
+       msleep(10);
+
+       parport_release(pp->pd);
+       parport_unregister_device(pp->pd);
+
+       pdev = to_platform_device(pp->bitbang.master->cdev.dev);
+
+       (void) spi_master_put(pp->bitbang.master);
+
+       platform_device_unregister(pdev);
+}
+
+static struct parport_driver butterfly_driver = {
+       .name =         "spi_butterfly",
+       .attach =       butterfly_attach,
+       .detach =       butterfly_detach,
+};
+
+
+static int __init butterfly_init(void)
+{
+       return parport_register_driver(&butterfly_driver);
+}
+device_initcall(butterfly_init);
+
+static void __exit butterfly_exit(void)
+{
+       parport_unregister_driver(&butterfly_driver);
+}
+module_exit(butterfly_exit);
+
+MODULE_LICENSE("GPL");
index 9baa6296fc95de6992a7795c948e5cf8b190f8c5..7af1883d4bf9cf127c183089ef52c8fbd5f2703d 100644 (file)
@@ -207,7 +207,7 @@ static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
 **  urbs  **
 ************/
 
-static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
+static struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
 {
        struct urb *urb;
 
@@ -224,7 +224,7 @@ static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
        return urb;
 }
 
-static inline int usbatm_submit_urb(struct urb *urb)
+static int usbatm_submit_urb(struct urb *urb)
 {
        struct usbatm_channel *channel = urb->context;
        int ret;
index 8f402f85e1ca71f09373866151fb51efa6322e2d..afc84cfb61f996fc484308473552deb880839734 100644 (file)
@@ -2534,9 +2534,6 @@ static struct usb_gadget_driver eth_driver = {
        .driver         = {
                .name           = (char *) shortname,
                .owner          = THIS_MODULE,
-               // .shutdown = ...
-               // .suspend = ...
-               // .resume = ...
        },
 };
 
index c6c279de832e40920fd58d0a36ba403b93fbb541..9a4edc5657aa695cb7f98030084433f6369435c9 100644 (file)
@@ -1738,9 +1738,6 @@ static struct usb_gadget_driver gadgetfs_driver = {
 
        .driver         = {
                .name           = (char *) shortname,
-               // .shutdown = ...
-               // .suspend = ...
-               // .resume = ...
        },
 };
 
index 2e6926b33455b0197bb58179c922acd42dadf76c..ba9acd5310247909145ac4493fee7d308650b7ea 100644 (file)
@@ -374,9 +374,6 @@ static struct usb_gadget_driver gs_gadget_driver = {
        .disconnect =           gs_disconnect,
        .driver = {
                .name =         GS_SHORT_NAME,
-               /* .shutdown = ... */
-               /* .suspend = ...  */
-               /* .resume = ...   */
        },
 };
 
index 6c58636e914b697d9dea954d77a48feb31b124ec..2fc110d3ad5ab05b960578280f108de6304b9502 100644 (file)
@@ -1303,9 +1303,6 @@ static struct usb_gadget_driver zero_driver = {
        .driver         = {
                .name           = (char *) shortname,
                .owner          = THIS_MODULE,
-               // .shutdown = ...
-               // .suspend = ...
-               // .resume = ...
        },
 };
 
index 509dd0a04c54f5e8e5bf9d4164a635133095c9ce..5246b35301de9d4e9333d1f14e15e51bea0919b5 100644 (file)
@@ -37,6 +37,16 @@ config USB_HIDINPUT
 
          If unsure, say Y.
 
+config USB_HIDINPUT_POWERBOOK
+       bool "Enable support for iBook/PowerBook special keys"
+       default n
+       depends on USB_HIDINPUT
+       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_HIDINPUT && EXPERIMENTAL
index 5f52979af1c736905ba0ed08f52dab03135a5d76..a91e72c41415c213b8ece5824c16f4873161dc73 100644 (file)
@@ -1450,6 +1450,9 @@ void hid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_APPLE            0x05ac
 #define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304
 
+#define USB_VENDOR_ID_CHERRY           0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -1580,6 +1583,16 @@ static const struct hid_blacklist {
        { 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, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN },
+
        { 0, 0 }
 };
 
@@ -1626,6 +1639,20 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
                usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma);
 }
 
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+
+static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
+{
+       if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+               info("Fixing up Cherry Cymotion report descriptor");
+               rdesc[11] = rdesc[16] = 0xff;
+               rdesc[12] = rdesc[17] = 0x03;
+       }
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1673,6 +1700,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                return NULL;
        }
 
+       if ((quirks & HID_QUIRK_CYMOTION))
+               hid_fixup_cymotion_descriptor(rdesc, rsize);
+
 #ifdef DEBUG_DATA
        printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
        for (n = 0; n < rsize; n++)
index 192a03b2897145ba00155ebe8d5e74f887ae2cdd..cb0d80f492520eeb42e5592cccd203ac81032a6a 100644 (file)
@@ -73,6 +73,160 @@ static const struct {
 #define map_key_clear(c)       do { map_key(c); clear_bit(c, bit); } while (0)
 #define map_ff_effect(c)       do { set_bit(c, input->ffbit); } while (0)
 
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+
+struct hidinput_key_translation {
+       u16 from;
+       u16 to;
+       u8 flags;
+};
+
+#define POWERBOOK_FLAG_FKEY 0x01
+
+static struct hidinput_key_translation powerbook_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN,     POWERBOOK_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,       POWERBOOK_FLAG_FKEY },
+       { KEY_F3,       KEY_MUTE,               POWERBOOK_FLAG_FKEY },
+       { KEY_F4,       KEY_VOLUMEDOWN,         POWERBOOK_FLAG_FKEY },
+       { KEY_F5,       KEY_VOLUMEUP,           POWERBOOK_FLAG_FKEY },
+       { KEY_F6,       KEY_NUMLOCK,            POWERBOOK_FLAG_FKEY },
+       { KEY_F7,       KEY_SWITCHVIDEOMODE,    POWERBOOK_FLAG_FKEY },
+       { KEY_F8,       KEY_KBDILLUMTOGGLE,     POWERBOOK_FLAG_FKEY },
+       { KEY_F9,       KEY_KBDILLUMDOWN,       POWERBOOK_FLAG_FKEY },
+       { KEY_F10,      KEY_KBDILLUMUP,         POWERBOOK_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+static struct hidinput_key_translation powerbook_numlock_keys[] = {
+       { KEY_J,        KEY_KP1 },
+       { KEY_K,        KEY_KP2 },
+       { KEY_L,        KEY_KP3 },
+       { KEY_U,        KEY_KP4 },
+       { KEY_I,        KEY_KP5 },
+       { KEY_O,        KEY_KP6 },
+       { KEY_7,        KEY_KP7 },
+       { KEY_8,        KEY_KP8 },
+       { KEY_9,        KEY_KP9 },
+       { KEY_M,        KEY_KP0 },
+       { KEY_DOT,      KEY_KPDOT },
+       { KEY_SLASH,    KEY_KPPLUS },
+       { KEY_SEMICOLON, KEY_KPMINUS },
+       { KEY_P,        KEY_KPASTERISK },
+       { KEY_MINUS,    KEY_KPEQUAL },
+       { KEY_0,        KEY_KPSLASH },
+       { KEY_F6,       KEY_NUMLOCK },
+       { KEY_KPENTER,  KEY_KPENTER },
+       { KEY_BACKSPACE, KEY_BACKSPACE },
+       { }
+};
+
+static int usbhid_pb_fnmode = 1;
+module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644);
+MODULE_PARM_DESC(pb_fnmode,
+       "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
+
+static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
+{
+       struct hidinput_key_translation *trans;
+
+       /* Look for the translation */
+       for (trans = table; trans->from; trans++)
+               if (trans->from == from)
+                       return trans;
+
+       return NULL;
+}
+
+static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+                            struct hid_usage *usage, __s32 value)
+{
+       struct hidinput_key_translation *trans;
+
+       if (usage->code == KEY_FN) {
+               if (value) hid->quirks |=  HID_QUIRK_POWERBOOK_FN_ON;
+               else       hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON;
+
+               input_event(input, usage->type, usage->code, value);
+
+               return 1;
+       }
+
+       if (usbhid_pb_fnmode) {
+               int do_translate;
+
+               trans = find_translation(powerbook_fn_keys, usage->code);
+               if (trans) {
+                       if (test_bit(usage->code, hid->pb_pressed_fn))
+                               do_translate = 1;
+                       else if (trans->flags & POWERBOOK_FLAG_FKEY)
+                               do_translate =
+                                       (usbhid_pb_fnmode == 2 &&  (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) ||
+                                       (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON));
+                       else
+                               do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON);
+
+                       if (do_translate) {
+                               if (value)
+                                       set_bit(usage->code, hid->pb_pressed_fn);
+                               else
+                                       clear_bit(usage->code, hid->pb_pressed_fn);
+
+                               input_event(input, usage->type, trans->to, value);
+
+                               return 1;
+                       }
+               }
+
+               if (test_bit(usage->code, hid->pb_pressed_numlock) ||
+                   test_bit(LED_NUML, input->led)) {
+                       trans = find_translation(powerbook_numlock_keys, usage->code);
+
+                       if (trans) {
+                               if (value)
+                                       set_bit(usage->code, hid->pb_pressed_numlock);
+                               else
+                                       clear_bit(usage->code, hid->pb_pressed_numlock);
+
+                               input_event(input, usage->type, trans->to, value);
+                       }
+
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void hidinput_pb_setup(struct input_dev *input)
+{
+       struct hidinput_key_translation *trans;
+
+       set_bit(KEY_NUMLOCK, input->keybit);
+
+       /* Enable all needed keys */
+       for (trans = powerbook_fn_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+
+       for (trans = powerbook_numlock_keys; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+}
+#else
+static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input,
+                                   struct hid_usage *usage, __s32 value)
+{
+       return 0;
+}
+
+static inline void hidinput_pb_setup(struct input_dev *input)
+{
+}
+#endif
+
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
                                     struct hid_usage *usage)
 {
@@ -135,8 +289,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case HID_UP_SIMULATION:
 
                        switch (usage->hid & 0xffff) {
-                               case 0xba: map_abs(ABS_RUDDER); break;
+                               case 0xba: map_abs(ABS_RUDDER);   break;
                                case 0xbb: map_abs(ABS_THROTTLE); break;
+                               case 0xc4: map_abs(ABS_GAS);      break;
+                               case 0xc5: map_abs(ABS_BRAKE);    break;
+                               case 0xc8: map_abs(ABS_WHEEL);    break;
                                default:   goto ignore;
                        }
                        break;
@@ -289,11 +446,19 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x226: map_key_clear(KEY_STOP);            break;
                                case 0x227: map_key_clear(KEY_REFRESH);         break;
                                case 0x22a: map_key_clear(KEY_BOOKMARKS);       break;
+                               case 0x233: map_key_clear(KEY_SCROLLUP);        break;
+                               case 0x234: map_key_clear(KEY_SCROLLDOWN);      break;
                                case 0x238: map_rel(REL_HWHEEL);                break;
                                case 0x279: map_key_clear(KEY_REDO);            break;
                                case 0x289: map_key_clear(KEY_REPLY);           break;
                                case 0x28b: map_key_clear(KEY_FORWARDMAIL);     break;
                                case 0x28c: map_key_clear(KEY_SEND);            break;
+
+                               /* Reported on a Cherry Cymotion keyboard */
+                               case 0x301: map_key_clear(KEY_PROG1);           break;
+                               case 0x302: map_key_clear(KEY_PROG2);           break;
+                               case 0x303: map_key_clear(KEY_PROG3);           break;
+
                                default:    goto ignore;
                        }
                        break;
@@ -325,7 +490,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
                        set_bit(EV_REP, input->evbit);
                        switch(usage->hid & HID_USAGE) {
-                               case 0x003: map_key_clear(KEY_FN);              break;
+                               case 0x003:
+                                       /* The fn key on Apple PowerBooks */
+                                       map_key_clear(KEY_FN);
+                                       hidinput_pb_setup(input);
+                                       break;
+
                                default:    goto ignore;
                        }
                        break;
@@ -482,6 +652,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
+       if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value))
+               return;
+
        if (usage->hat_min < usage->hat_max || usage->hat_dir) {
                int hat_dir = usage->hat_dir;
                if (!hat_dir)
@@ -524,7 +697,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
-       if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
+       if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
                return;
 
        input_event(input, usage->type, usage->code, value);
index ee48a227610420ec42c6c2334430bfb3a2053bfd..8b0d4346ce9c569b67e92036995b88bc62038902 100644 (file)
@@ -235,17 +235,20 @@ struct hid_item {
  * HID device quirks.
  */
 
-#define HID_QUIRK_INVERT                       0x001
-#define HID_QUIRK_NOTOUCH                      0x002
-#define HID_QUIRK_IGNORE                       0x004
-#define HID_QUIRK_NOGET                                0x008
-#define HID_QUIRK_HIDDEV                       0x010
-#define HID_QUIRK_BADPAD                       0x020
-#define HID_QUIRK_MULTI_INPUT                  0x040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7          0x080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x200
-#define HID_QUIRK_2WHEEL_POWERMOUSE            0x400
+#define HID_QUIRK_INVERT                       0x00000001
+#define HID_QUIRK_NOTOUCH                      0x00000002
+#define HID_QUIRK_IGNORE                       0x00000004
+#define HID_QUIRK_NOGET                                0x00000008
+#define HID_QUIRK_HIDDEV                       0x00000010
+#define HID_QUIRK_BADPAD                       0x00000020
+#define HID_QUIRK_MULTI_INPUT                  0x00000040
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_7          0x00000080
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_5          0x00000100
+#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON         0x00000200
+#define HID_QUIRK_2WHEEL_POWERMOUSE            0x00000400
+#define HID_QUIRK_CYMOTION                     0x00000800
+#define HID_QUIRK_POWERBOOK_HAS_FN             0x00001000
+#define HID_QUIRK_POWERBOOK_FN_ON              0x00002000
 
 /*
  * This is the global environment of the parser. This information is
@@ -431,6 +434,11 @@ struct hid_device {                                                        /* device report descriptor */
        void (*ff_exit)(struct hid_device*);                            /* Called by hid_exit_ff(hid) */
        int (*ff_event)(struct hid_device *hid, struct input_dev *input,
                        unsigned int type, unsigned int code, int value);
+
+#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
+       unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
+       unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
+#endif
 };
 
 #define HID_GLOBAL_STACK_SIZE 4
index 19e015d171aab767a7df15582dded3958b7b8feb..d9d9f656b8c9ea26f576a11feb451798a886cd4a 100644 (file)
@@ -259,7 +259,7 @@ static int hid_pid_upload_effect(struct input_dev *dev,
 int hid_pid_init(struct hid_device *hid)
 {
        struct hid_ff_pid *private;
-       struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list);
+       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
        struct input_dev *input_dev = hidinput->input;
 
        private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
index 48df4cfd5a42274b7a756f37ce6869c646a590e3..d3e15df9e815ec32d819aa57b9c42544193cae7b 100644 (file)
@@ -95,7 +95,7 @@ MODULE_LICENSE(DRIVER_LICENSE);
 enum {
        PENPARTNER = 0,
        GRAPHIRE,
-       G4,
+       WACOM_G4,
        PL,
        INTUOS,
        INTUOS3,
@@ -373,7 +373,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
 
                        case 2: /* Mouse with wheel */
                                input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
-                               if (wacom->features->type == G4) {
+                               if (wacom->features->type == WACOM_G4) {
                                        rw = data[7] & 0x04 ? -(data[7] & 0x03) : (data[7] & 0x03);
                                        input_report_rel(dev, REL_WHEEL, rw);
                                } else
@@ -385,7 +385,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
                                id = CURSOR_DEVICE_ID;
                                input_report_key(dev, BTN_LEFT, data[1] & 0x01);
                                input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
-                               if (wacom->features->type == G4)
+                               if (wacom->features->type == WACOM_G4)
                                        input_report_abs(dev, ABS_DISTANCE, data[6]);
                                else
                                        input_report_abs(dev, ABS_DISTANCE, data[7]);
@@ -410,7 +410,7 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
        input_sync(dev);
 
        /* send pad data */
-       if (wacom->features->type == G4) {
+       if (wacom->features->type == WACOM_G4) {
                /* fist time sending pad data */
                if (wacom->tool[1] != BTN_TOOL_FINGER) {
                        wacom->id[1] = 0;
@@ -713,8 +713,8 @@ static struct wacom_features wacom_features[] = {
        { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 32, GRAPHIRE,   wacom_graphire_irq },
        { "Wacom Graphire3",     8,  10208,  7424,  511, 32, GRAPHIRE,   wacom_graphire_irq },
        { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 32, GRAPHIRE,   wacom_graphire_irq },
-       { "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 32, G4,         wacom_graphire_irq },
-       { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 32, G4,         wacom_graphire_irq },
+       { "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 32, WACOM_G4,   wacom_graphire_irq },
+       { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 32, WACOM_G4,   wacom_graphire_irq },
        { "Wacom Volito",        8,   5104,  3712,  511, 32, GRAPHIRE,   wacom_graphire_irq },
        { "Wacom PenStation2",   8,   3250,  2320,  255, 32, GRAPHIRE,   wacom_graphire_irq },
        { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 32, GRAPHIRE,   wacom_graphire_irq },
@@ -859,7 +859,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
        input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0);
 
        switch (wacom->features->type) {
-               case G4:
+               case WACOM_G4:
                        input_dev->evbit[0] |= BIT(EV_MSC);
                        input_dev->mscbit[0] |= BIT(MSC_SERIAL);
                        input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
index 664139afcfa9a7a28b09de9fac830592be169fd3..e9f9f4bafa17568eecd17b030e014790d792909b 100644 (file)
@@ -37,11 +37,6 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
        return 0;
 }
 
-struct bus_type usb_serial_bus_type = {
-       .name =         "usb-serial",
-       .match =        usb_serial_device_match,
-};
-
 static int usb_serial_device_probe (struct device *dev)
 {
        struct usb_serial_driver *driver;
@@ -109,14 +104,18 @@ exit:
        return retval;
 }
 
+struct bus_type usb_serial_bus_type = {
+       .name =         "usb-serial",
+       .match =        usb_serial_device_match,
+       .probe =        usb_serial_device_probe,
+       .remove =       usb_serial_device_remove,
+};
+
 int usb_serial_bus_register(struct usb_serial_driver *driver)
 {
        int retval;
 
        driver->driver.bus = &usb_serial_bus_type;
-       driver->driver.probe = usb_serial_device_probe;
-       driver->driver.remove = usb_serial_device_remove;
-
        retval = driver_register(&driver->driver);
 
        return retval;
index 9ffff1938239c97bc878160c73f3e890a28d2d36..0eb883f44adaee3bfde6c2879ca63a7e98ae668a 100644 (file)
@@ -43,8 +43,6 @@ static int debug;
 #define PL2303_BUF_SIZE                1024
 #define PL2303_TMP_BUF_SIZE    1024
 
-static DECLARE_MUTEX(pl2303_tmp_buf_sem);
-
 struct pl2303_buf {
        unsigned int    buf_size;
        char            *buf_buf;
index 3b0ddc55236b7624a5ee48a2fad150711ad90f35..78488bb41aeb1d984ba6f2a32f485378c07f883f 100644 (file)
@@ -102,8 +102,7 @@ static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                         u_int transp, struct fb_info *info);
 static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
                           struct fb_info *info);
-static int mc68x328fb_mmap(struct fb_info *info, struct file *file,
-                   struct vm_area_struct *vma);
+static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 
 static struct fb_ops mc68x328fb_ops = {
        .fb_check_var   = mc68x328fb_check_var,
@@ -398,8 +397,7 @@ static int mc68x328fb_pan_display(struct fb_var_screeninfo *var,
      *  Most drivers don't need their own mmap function 
      */
 
-static int mc68x328fb_mmap(struct fb_info *info, struct file *file,
-                   struct vm_area_struct *vma)
+static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
 #ifndef MMU
        /* this is uClinux (no MMU) specific code */
index 750cebb183063d6eee8b81c36daca65be32e2228..b058273527bbde69e463af63f49cad6ccb26727d 100644 (file)
@@ -883,7 +883,7 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
  * Note that we are entered with the kernel locked.
  */
 static int
-acornfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        unsigned long off, start;
        u32 len;
index 0da4083ba908b04e1f38d19fdb54df2cdaab1fb8..b2187175d03fcde37c6daa66f240b0cdb36c4a71 100644 (file)
@@ -307,7 +307,7 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
        return 0;
 }
 
-static int clcdfb_mmap(struct fb_info *info, struct file *file,
+static int clcdfb_mmap(struct fb_info *info,
                       struct vm_area_struct *vma)
 {
        struct clcd_fb *fb = to_clcd(info);
index 2c42a812655a14a977e963a7aeb7bb0898afec01..3033c72dea200ae7252170ee36efb882be662782 100644 (file)
@@ -1131,9 +1131,7 @@ static void amifb_copyarea(struct fb_info *info,
                           const struct fb_copyarea *region);
 static void amifb_imageblit(struct fb_info *info,
                            const struct fb_image *image);
-static int amifb_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg,
-                      struct fb_info *info);
+static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
 
 
        /*
@@ -2172,9 +2170,8 @@ static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
         * Amiga Frame Buffer Specific ioctls
         */
 
-static int amifb_ioctl(struct inode *inode, struct file *file,
-                      unsigned int cmd, unsigned long arg,
-                      struct fb_info *info)
+static int amifb_ioctl(struct fb_info *info,
+                      unsigned int cmd, unsigned long arg)
 {
        union {
                struct fb_fix_cursorinfo fix;
index 89060b2db8e5f1bf5c6aae4d10eb0f8899927a7a..df8e5667b348efa317be6d5732e2e478162d0e22 100644 (file)
@@ -399,9 +399,8 @@ static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
                                image->height);
 }
 
-static int arcfb_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg,
-                         struct fb_info *info)
+static int arcfb_ioctl(struct fb_info *info,
+                         unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
        struct arcfb_par *par = info->par;
index 15ec1295bc294eefea5a3d8ba049467a2f336f48..e69ab65f7843b99c6ee37f3284d8a3fa47777b27 100644 (file)
@@ -2571,8 +2571,7 @@ atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 }
 
 static int
-atafb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-              unsigned long arg, int con, struct fb_info *info)
+atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        switch (cmd) {
 #ifdef FBCMD_GET_CURRENTPAR
index e686185a076d0ee52fabf164f8fa39abc9a66a0c..bfc8a93b2c73baad26e81a034961c70df0999186 100644 (file)
@@ -431,8 +431,7 @@ static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 static int aty128fb_pan_display(struct fb_var_screeninfo *var,
                           struct fb_info *fb);
 static int aty128fb_blank(int blank, struct fb_info *fb);
-static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                         u_long arg, struct fb_info *info);
+static int aty128fb_ioctl(struct fb_info *info, u_int cmd, unsigned long arg);
 static int aty128fb_sync(struct fb_info *info);
 
     /*
@@ -2108,8 +2107,7 @@ static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 /* in param: u32*      backlight value: 0 to 15 */
 #define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32)
 
-static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-                         u_long arg, struct fb_info *info)
+static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct aty128fb_par *par = info->par;
        u32 value;
index ed81005cbdba51cdf2fd06c318083fa063cb839c..485be386a8ffb32958b1f5dd3527cb9b865fd22a 100644 (file)
@@ -238,13 +238,12 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        u_int transp, struct fb_info *info);
 static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
 static int atyfb_blank(int blank, struct fb_info *info);
-static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-       u_long arg, struct fb_info *info);
+static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
 extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
 #ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
+static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
 #endif
 static int atyfb_sync(struct fb_info *info);
 
@@ -1739,8 +1738,7 @@ struct atyclk {
 #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
 #endif
 
-static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-       u_long arg, struct fb_info *info)
+static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
 #ifdef __sparc__
@@ -1845,7 +1843,7 @@ static int atyfb_sync(struct fb_info *info)
 }
 
 #ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
        unsigned int size, page, map_size = 0;
index 156db84cb36371aa4709b293b25492e49b71f099..c9f0c5a07e6e6c469d9131030a753d9116da9e73 100644 (file)
@@ -864,8 +864,8 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
 }
 
 
-static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-                           unsigned long arg, struct fb_info *info)
+static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
+                           unsigned long arg)
 {
         struct radeonfb_info *rinfo = info->par;
        unsigned int tmp;
index 097d668c4fe5932df13b40b2fcf08d8939321b8b..556895e9964509d891ed7984767ce599129053c0 100644 (file)
@@ -2734,7 +2734,7 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
         * BIOS does tho. Right now, all this PM stuff is pmac-only for that
         * reason. --BenH
         */
-#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF)
+#if defined(CONFIG_PM) && defined(CONFIG_PPC_PMAC)
        if (_machine == _MACH_Pmac && rinfo->of_node) {
                if (rinfo->is_mobility && rinfo->pm_reg &&
                    rinfo->family <= CHIP_FAMILY_RV250)
@@ -2778,12 +2778,12 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
                OUTREG(TV_DAC_CNTL, INREG(TV_DAC_CNTL) | 0x07000000);
 #endif
        }
-#endif /* defined(CONFIG_PM) && defined(CONFIG_PPC_OF) */
+#endif /* defined(CONFIG_PM) && defined(CONFIG_PPC_PMAC) */
 }
 
 void radeonfb_pm_exit(struct radeonfb_info *rinfo)
 {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC_OF)
+#if defined(CONFIG_PM) && defined(CONFIG_PPC_PMAC)
        if (rinfo->pm_mode != radeon_pm_none)
                pmac_set_early_video_resume(NULL, NULL);
 #endif
index a5129806172fb0684980eb685cf9a84f20fe58e7..2406899f12078fd5d958a6b9495a3f6e33564fe3 100644 (file)
@@ -379,7 +379,7 @@ void au1100fb_fb_rotate(struct fb_info *fbi, int angle)
  * Map video memory in user space. We don't use the generic fb_mmap method mainly
  * to allow the use of the TLB streaming flag (CCA=6)
  */
-int au1100fb_fb_mmap(struct fb_info *fbi, struct file *file, struct vm_area_struct *vma)
+int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
 {
        struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
        unsigned int len;
index 9248fe1fbb1a45e36e650058c566971f9aa232d3..c029db4646f6b8e1834aec1ad174b46ae0bc3bd2 100644 (file)
@@ -35,9 +35,8 @@
 
 static int bw2_blank(int, struct fb_info *);
 
-static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int bw2_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
+static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -169,7 +168,7 @@ static struct sbus_mmap_map bw2_mmap_map[] = {
        { .size = 0 }
 };
 
-static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct bw2_par *par = (struct bw2_par *)info->par;
 
@@ -181,8 +180,7 @@ static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  vma);
 }
 
-static int bw2_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct bw2_par *par = (struct bw2_par *) info->par;
 
index a56147102abbbaebcdac2ca6d80d530234ae756e..63b6c79c8a0a98195c00a59cfed6387d57f61f15 100644 (file)
@@ -31,9 +31,8 @@
 static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
                         unsigned, struct fb_info *);
 
-static int cg14_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int cg14_ioctl(struct inode *, struct file *, unsigned int,
-                     unsigned long, struct fb_info *);
+static int cg14_mmap(struct fb_info *, struct vm_area_struct *);
+static int cg14_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int cg14_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -268,7 +267,7 @@ static int cg14_setcolreg(unsigned regno,
        return 0;
 }
 
-static int cg14_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct cg14_par *par = (struct cg14_par *) info->par;
 
@@ -277,8 +276,7 @@ static int cg14_mmap(struct fb_info *info, struct file *file, struct vm_area_str
                                  par->iospace, vma);
 }
 
-static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                     unsigned long arg, struct fb_info *info)
+static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct cg14_par *par = (struct cg14_par *) info->par;
        struct cg14_regs __iomem *regs = par->regs;
index 9fcd89608ed7d6daa4ea4bd88ed4447b23845b59..3de6e1b5ab2f4008efd29b32805c9e3bd874dec1 100644 (file)
@@ -33,9 +33,8 @@ static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
                         unsigned, struct fb_info *);
 static int cg3_blank(int, struct fb_info *);
 
-static int cg3_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int cg3_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int cg3_mmap(struct fb_info *, struct vm_area_struct *);
+static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -230,7 +229,7 @@ static struct sbus_mmap_map cg3_mmap_map[] = {
        { .size = 0 }
 };
 
-static int cg3_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct cg3_par *par = (struct cg3_par *)info->par;
 
@@ -240,8 +239,7 @@ static int cg3_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  vma);
 }
 
-static int cg3_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct cg3_par *par = (struct cg3_par *) info->par;
 
index 050835e39aa3569769e25e00bc18cfdeb2161b5a..7aab91ead6818ee70d7484aedacc001a6ecd8739 100644 (file)
@@ -36,9 +36,8 @@ static int cg6_blank(int, struct fb_info *);
 static void cg6_imageblit(struct fb_info *, const struct fb_image *);
 static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
 static int cg6_sync(struct fb_info *);
-static int cg6_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int cg6_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
+static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -524,7 +523,7 @@ static struct sbus_mmap_map cg6_mmap_map[] = {
        { .size = 0 }
 };
 
-static int cg6_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct cg6_par *par = (struct cg6_par *)info->par;
 
@@ -534,8 +533,7 @@ static int cg6_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  vma);
 }
 
-static int cg6_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct cg6_par *par = (struct cg6_par *) info->par;
 
index 03798e9c882d813d2ab0a62a1b85f5e3272273f8..655301a8671c139f4ead17f56b05ad89a3a26d03 100644 (file)
@@ -128,7 +128,7 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var,
 static int controlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        u_int transp, struct fb_info *info);
 static int controlfb_blank(int blank_mode, struct fb_info *info);
-static int controlfb_mmap(struct fb_info *info, struct file *file,
+static int controlfb_mmap(struct fb_info *info,
        struct vm_area_struct *vma);
 static int controlfb_set_par (struct fb_info *info);
 static int controlfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);
@@ -280,7 +280,7 @@ static int controlfb_pan_display(struct fb_var_screeninfo *var,
  * for controlfb.
  * Note there's no locking in here; it's done in fb_mmap() in fbmem.c.
  */
-static int controlfb_mmap(struct fb_info *info, struct file *file,
+static int controlfb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
        unsigned long off, start;
index 32a9b69becc51d32764b6a75cbdfdad471dc5af7..d2dede6ed3e5c44bda0906208daf9dca1965f001 100644 (file)
@@ -957,7 +957,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
        default:
                if (fb->fb_ioctl == NULL)
                        return -EINVAL;
-               return fb->fb_ioctl(inode, file, cmd, arg, info);
+               return fb->fb_ioctl(info, cmd, arg);
        }
 }
 
@@ -1107,7 +1107,7 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        default:
                if (fb->fb_compat_ioctl)
-                       ret = fb->fb_compat_ioctl(file, cmd, arg, info);
+                       ret = fb->fb_compat_ioctl(info, cmd, arg);
                break;
        }
        unlock_kernel();
@@ -1135,7 +1135,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
        if (fb->fb_mmap) {
                int res;
                lock_kernel();
-               res = fb->fb_mmap(info, file, vma);
+               res = fb->fb_mmap(info, vma);
                unlock_kernel();
                return res;
        }
index c4870d559afc47d7a644d081ef548ef64717685c..9c9b21d469a1e7c76c1f3eac8ffb4ae9e4b6d6bd 100644 (file)
@@ -37,9 +37,8 @@ static void ffb_imageblit(struct fb_info *, const struct fb_image *);
 static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);
 static int ffb_sync(struct fb_info *);
-static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int ffb_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int ffb_mmap(struct fb_info *, struct vm_area_struct *);
+static int ffb_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -839,7 +838,7 @@ static struct sbus_mmap_map ffb_mmap_map[] = {
        { .size = 0 }
 };
 
-static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct ffb_par *par = (struct ffb_par *)info->par;
 
@@ -848,8 +847,7 @@ static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  0, vma);
 }
 
-static int ffb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct ffb_par *par = (struct ffb_par *) info->par;
 
index d744c51807b73af9420abaea6397f5f96afc7af3..38d22729b129ad713f49b66b068b699d5c609906 100644 (file)
@@ -979,7 +979,7 @@ static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-static int gbefb_mmap(struct fb_info *info, struct file *file,
+static int gbefb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
        unsigned long size = vma->vm_end - vma->vm_start;
@@ -1000,7 +1000,6 @@ static int gbefb_mmap(struct fb_info *info, struct file *file,
                pgprot_fb(pgprot_val(vma->vm_page_prot));
 
        vma->vm_flags |= VM_IO | VM_RESERVED;
-       vma->vm_file = file;
 
        /* look for the starting tile */
        tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];
index 8e8da743399416eafa71a730f50cca80a4b1f1e8..20e69156d7289cc9f3d1c63066ab753527deeb16 100644 (file)
@@ -215,11 +215,11 @@ static int __init gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *d
        if (ret < 0)
                return ret;
 
-       ret = pci_request_region(dev, 1, "gx1fb (video)");
+       ret = pci_request_region(dev, 0, "gx1fb (video)");
        if (ret < 0)
                return ret;
-       par->vid_regs = ioremap(pci_resource_start(dev, 1),
-                               pci_resource_len(dev, 1));
+       par->vid_regs = ioremap(pci_resource_start(dev, 0),
+                               pci_resource_len(dev, 0));
        if (!par->vid_regs)
                return -ENOMEM;
 
@@ -229,12 +229,9 @@ static int __init gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *d
        if (!par->dc_regs)
                return -ENOMEM;
 
-       ret = pci_request_region(dev, 0, "gx1fb (frame buffer)");
-       if (ret < 0 )
-               return -EBUSY;
        if ((fb_len = gx1_frame_buffer_size()) < 0)
                return -ENOMEM;
-       info->fix.smem_start = pci_resource_start(dev, 0);
+       info->fix.smem_start = gx_base + 0x800000;
        info->fix.smem_len = fb_len;
        info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
        if (!info->screen_base)
index e326f44f652d74668accbac05865c53288e4da61..6b88050d21bfbb4ae37bd96dbab85fcda267c5b8 100644 (file)
@@ -219,7 +219,7 @@ static void iga_blank_border(struct iga_par *par)
 }
 
 #ifdef __sparc__
-static int igafb_mmap(struct fb_info *info, struct file *file,
+static int igafb_mmap(struct fb_info *info,
                      struct vm_area_struct *vma)
 {
        struct iga_par *par = (struct iga_par *)info->par;
index a5d813050db574ed36548ee82d848fcf46fd03de..ad416ae475963650a782e8c33b7f0e82a79cc298 100644 (file)
@@ -1267,8 +1267,7 @@ imsttfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 #define FBIMSTT_GETIDXREG      0x545406
 
 static int
-imsttfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-             u_long arg, struct fb_info *info)
+imsttfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct imstt_par *par = info->par;
        void __user *argp = (void __user *)arg;
index 0090544842f5d672225b127c9f69f53ec31ebe63..6b8bd3cdf9c08f38fb9269c8da75a24b7267eb43 100644 (file)
@@ -157,9 +157,8 @@ static int intelfb_cursor(struct fb_info *info,
 
 static int intelfb_sync(struct fb_info *info);
 
-static int intelfb_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg,
-                        struct fb_info *info);
+static int intelfb_ioctl(struct fb_info *info,
+                        unsigned int cmd, unsigned long arg);
 
 static int __devinit intelfb_pci_register(struct pci_dev *pdev,
                                          const struct pci_device_id *ent);
@@ -1380,8 +1379,7 @@ intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 
 /* When/if we have our own ioctls. */
 static int
-intelfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-             unsigned long arg, struct fb_info *info)
+intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        int retval = 0;
 
index bcd359b6d4ff5a86dd31b48e1d9008c4e0f254bc..477ad297de4e03f7a9096c745ef2f885d878dde2 100644 (file)
@@ -586,9 +586,8 @@ static int __init kyrofb_setup(char *options)
 }
 #endif
 
-static int kyrofb_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg,
-                       struct fb_info *info)
+static int kyrofb_ioctl(struct fb_info *info,
+                       unsigned int cmd, unsigned long arg)
 {
        overlay_create ol_create;
        overlay_viewport_set ol_viewport_set;
index 494287f8f8bf5d3b3aced8b755f8e5def8598456..a23cfdb9d826391ff5d4007fb33f884da0d53f1c 100644 (file)
@@ -32,9 +32,8 @@ static int leo_setcolreg(unsigned, unsigned, unsigned, unsigned,
                         unsigned, struct fb_info *);
 static int leo_blank(int, struct fb_info *);
 
-static int leo_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int leo_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int leo_mmap(struct fb_info *, struct vm_area_struct *);
+static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -363,7 +362,7 @@ static struct sbus_mmap_map leo_mmap_map[] = {
        { .size = 0 }
 };
 
-static int leo_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct leo_par *par = (struct leo_par *)info->par;
 
@@ -373,8 +372,7 @@ static int leo_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  vma);
 }
 
-static int leo_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct leo_par *par = (struct leo_par *) info->par;
 
index 1e74f4cca53b2955d02cef90f29eaf5b4df10227..4055ff6f5a81c78d8fa53f9eda743983c7d176be 100644 (file)
@@ -865,9 +865,8 @@ static struct matrox_altout panellink_output = {
        .name    = "Panellink output",
 };
 
-static int matroxfb_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg,
-                         struct fb_info *info)
+static int matroxfb_ioctl(struct fb_info *info,
+                         unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
        MINFO_FROM_INFO(info);
index d52d7d825c41439ccb7825b0ea9be41d363ae303..27eb4bb4f89fe2000aa2dbeda19a3c1a40a3387c 100644 (file)
@@ -419,11 +419,10 @@ static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, stru
        return 0;
 }
 
-static int matroxfb_dh_ioctl(struct inode* inode,
-               struct file* file,
+static int matroxfb_dh_ioctl(struct fb_info *info,
                unsigned int cmd,
-               unsigned long arg,
-               struct fb_info* info) {
+               unsigned long arg)
+{
 #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon))
        MINFO_FROM(m2info->primary_dev);
 
@@ -457,7 +456,7 @@ static int matroxfb_dh_ioctl(struct inode* inode,
                case MATROXFB_GET_OUTPUT_MODE:
                case MATROXFB_GET_ALL_OUTPUTS:
                        {
-                               return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon));
+                               return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(&ACCESS_FBINFO(fbcon), cmd, arg);
                        }
                case MATROXFB_SET_OUTPUT_CONNECTION:
                        {
index a1f2c5e8fc88ff97553d2524c63da92baf854b6f..6019710dc298513c819c1fc419a24a29d5427118 100644 (file)
@@ -968,7 +968,7 @@ static inline int maven_compute_timming(struct maven_data* md,
        return 0;
 }
 
-static inline int maven_program_timming(struct maven_data* md,
+static int maven_program_timming(struct maven_data* md,
                const struct mavenregs* m) {
        struct i2c_client* c = md->client;
 
index e18c9f98a40188f1deccea933f7f4607371a33a1..747602aa56158976aa5b7ce67aed28d72e2aa1ee 100644 (file)
@@ -853,7 +853,7 @@ static int neofb_set_par(struct fb_info *info)
        /* If the user did not specify any display devices, then... */
        if (par->PanelDispCntlReg1 == 0x00) {
                /* Default to internal (i.e., LCD) only. */
-               par->PanelDispCntlReg1 |= 0x02;
+               par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
        }
 
        /* If we are using a fixed mode, then tell the chip we are. */
index b251e754e16cff62afdc08b4c96883df031060a6..0d19575053598b665a6d425805672860e614bb6b 100644 (file)
@@ -31,9 +31,8 @@ static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned,
                           unsigned, struct fb_info *);
 static int p9100_blank(int, struct fb_info *);
 
-static int p9100_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int p9100_ioctl(struct inode *, struct file *, unsigned int,
-                      unsigned long, struct fb_info *);
+static int p9100_mmap(struct fb_info *, struct vm_area_struct *);
+static int p9100_ioctl(struct fb_info *, unsigned int, unsigned long);
 
 /*
  *  Frame buffer operations
@@ -222,7 +221,7 @@ static struct sbus_mmap_map p9100_mmap_map[] = {
        { 0,                    0,              0                   }
 };
 
-static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct p9100_par *par = (struct p9100_par *)info->par;
 
@@ -232,8 +231,8 @@ static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_st
                                  vma);
 }
 
-static int p9100_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                      unsigned long arg, struct fb_info *info)
+static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
+                      unsigned long arg)
 {
        struct p9100_par *par = (struct p9100_par *) info->par;
 
index 2e11b601c488cb63f4e0d815f258d03cda74bf12..0e78ddc81583dfe3a42b1ef2158346ed39699de5 100644 (file)
@@ -657,9 +657,7 @@ static void pm3fb_set_disp(const void *par, struct display *disp,
 static void pm3fb_detect(void);
 static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
                             struct fb_info_gen *info);
-static int pm3fb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, int con,
-                      struct fb_info *info);
+static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
 
 
 /* the struct that hold them together */
@@ -3438,9 +3436,7 @@ static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
        return 0;
 }
 
-static int pm3fb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, int con,
-                      struct fb_info *info)
+static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
        u32 cm, i;
index 28d1fe5fe34007fcdf9996cb0216154732e74f1e..d92f352211efcdce0340ba94907b60d51d995d3d 100644 (file)
@@ -299,8 +299,7 @@ static int aafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
                return -EINVAL;
 }
 
-static int aafb_ioctl(struct inode *inode, struct file *file, u32 cmd,
-                     unsigned long arg, int con, struct fb_info *info)
+static int aafb_ioctl(struct fb_info *info, u32 cmd, unsigned long arg)
 {
        /* TODO: Not yet implemented */
        return -ENOIOCTLCMD;
index 9fc10b9e6f578115ce97d28ac7503cb477bfecf3..53ad61f1038c2026adc21c2ca867fa338bcec380 100644 (file)
@@ -395,7 +395,7 @@ static int pxafb_blank(int blank, struct fb_info *info)
        return 0;
 }
 
-static int pxafb_mmap(struct fb_info *info, struct file *file,
+static int pxafb_mmap(struct fb_info *info,
                      struct vm_area_struct *vma)
 {
        struct pxafb_info *fbi = (struct pxafb_info *)info;
index 600318f708f294e2aafd4e2c04aa9767778735b8..db9fb9074dbcbfdb21846a55b2e1add84c9e4bbb 100644 (file)
@@ -1497,8 +1497,8 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
 }
 
 
-static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-                           unsigned long arg, struct fb_info *info)
+static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
+                           unsigned long arg)
 {
         struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
        unsigned int tmp;
index 087e58689e4c46486bfde6331db3e6f37e8e33fe..8a893ce7040de1feae90633d46c5800c95357ef1 100644 (file)
@@ -815,7 +815,7 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
        return 0;
 }
 
-static int sa1100fb_mmap(struct fb_info *info, struct file *file,
+static int sa1100fb_mmap(struct fb_info *info,
                         struct vm_area_struct *vma)
 {
        struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
index 7054660767e46eb90326b506b4b7b518c87d19ee..2e6df1fcb2b926e875508bc8ff3181bb4d89a7bc 100644 (file)
@@ -115,7 +115,7 @@ static int sgivwfb_set_par(struct fb_info *info);
 static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
                             u_int blue, u_int transp,
                             struct fb_info *info);
-static int sgivwfb_mmap(struct fb_info *info, struct file *file,
+static int sgivwfb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma);
 
 static struct fb_ops sgivwfb_ops = {
@@ -706,7 +706,7 @@ static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
        return 0;
 }
 
-static int sgivwfb_mmap(struct fb_info *info, struct file *file,
+static int sgivwfb_mmap(struct fb_info *info,
                        struct vm_area_struct *vma)
 {
        unsigned long size = vma->vm_end - vma->vm_start;
@@ -723,7 +723,6 @@ static int sgivwfb_mmap(struct fb_info *info, struct file *file,
        if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
                                                size, vma->vm_page_prot))
                return -EAGAIN;
-       vma->vm_file = file;
        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
               offset, vma->vm_start);
        return 0;
index dea1a46c67c4fe232e24874fd08f15f46e7702b3..8adf5bf91eee075716b12d95d5eb26ef6c0312bc 100644 (file)
@@ -1743,13 +1743,14 @@ sisfb_blank(int blank, struct fb_info *info)
 
 /* ----------- FBDev related routines for all series ---------- */
 
-static int
-sisfb_ioctl(struct inode *inode, struct file *file,
-            unsigned int cmd, unsigned long arg,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-           int con,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int     sisfb_ioctl(struct fb_info *info, unsigned int cmd,
+                           unsigned long arg)
+#else
+static int     sisfb_ioctl(struct inode *inode, struct file *file,
+                               unsigned int cmd, unsigned long arg,
+                               struct fb_info *info)
 #endif
-           struct fb_info *info)
 {
        struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
        struct sis_memreq       sismemreq;
@@ -1924,19 +1925,6 @@ sisfb_ioctl(struct inode *inode, struct file *file,
        return 0;
 }
 
-#ifdef SIS_NEW_CONFIG_COMPAT
-static long
-sisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info)
-{
-       int ret;
-
-       lock_kernel();
-       ret = sisfb_ioctl(NULL, f, cmd, arg, info);
-       unlock_kernel();
-       return ret;
-}
-#endif
-
 static int
 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 {
@@ -2007,7 +1995,7 @@ static struct fb_ops sisfb_ops = {
 #endif
        .fb_sync        = fbcon_sis_sync,
 #ifdef SIS_NEW_CONFIG_COMPAT
-       .fb_compat_ioctl= sisfb_compat_ioctl,
+       .fb_compat_ioctl= sisfb_ioctl,
 #endif
        .fb_ioctl       = sisfb_ioctl
 };
index 445bcbba03aefd54e336c5c1f436bf4d858bfe75..70b6df371b8e7f72231c91c9bbc32efb9c1fdb28 100644 (file)
@@ -727,9 +727,14 @@ static int sisfb_ioctl(struct inode *inode, struct file *file,
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int     sisfb_ioctl(struct fb_info *info, unsigned int cmd,
+                           unsigned long arg);
+#else
 static int     sisfb_ioctl(struct inode *inode, struct file *file,
                                unsigned int cmd, unsigned long arg,
                                struct fb_info *info);
+#endif
 static int     sisfb_set_par(struct fb_info *info);
 static int     sisfb_blank(int blank,
                                struct fb_info *info);
index 8a5ce210bb27c6b6876dc83bf1b250819f49f32b..99921df35474d079dd696b4f1ebd98fe98efb458 100644 (file)
@@ -771,8 +771,7 @@ static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        return 0;
 }
 
-static int sstfb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, struct fb_info *info )
+static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
 {
        struct sstfb_par *par = info->par;
        struct pci_dev *sst_dev = par->dev;
index 2b27b4474001d66020a28fadc2b42080b82d620b..95b918229d9b13e6f35879d39ccc78924f43ec7c 100644 (file)
@@ -33,9 +33,8 @@ static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned,
                         unsigned, struct fb_info *);
 static int tcx_blank(int, struct fb_info *);
 
-static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int tcx_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int tcx_mmap(struct fb_info *, struct vm_area_struct *);
+static int tcx_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -302,7 +301,7 @@ static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = {
        { .size = 0 }
 };
 
-static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct tcx_par *par = (struct tcx_par *)info->par;
 
@@ -312,8 +311,8 @@ static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  vma);
 }
 
-static int tcx_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int tcx_ioctl(struct fb_info *info, unsigned int cmd,
+                    unsigned long arg)
 {
        struct tcx_par *par = (struct tcx_par *) info->par;
 
index ffa1ad474226c5e121486ba8c0f4f87c8bc91f70..53208cb58396a8a1a047232f3de9c7ef7dd57f12 100644 (file)
@@ -81,7 +81,7 @@ static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                         u_int transp, struct fb_info *info);
 static int vfb_pan_display(struct fb_var_screeninfo *var,
                           struct fb_info *info);
-static int vfb_mmap(struct fb_info *info, struct file *file,
+static int vfb_mmap(struct fb_info *info,
                    struct vm_area_struct *vma);
 
 static struct fb_ops vfb_ops = {
@@ -368,7 +368,7 @@ static int vfb_pan_display(struct fb_var_screeninfo *var,
      *  Most drivers don't need their own mmap function 
      */
 
-static int vfb_mmap(struct fb_info *info, struct file *file,
+static int vfb_mmap(struct fb_info *info,
                    struct vm_area_struct *vma)
 {
        return -EINVAL;
index ccba227676f274f4321163f7df396f8a1ac4e710..fcbee748c59227b2f344ab483be2558d93e749c5 100644 (file)
@@ -77,7 +77,6 @@ int zorro_register_driver(struct zorro_driver *drv)
        /* initialize common driver fields */
        drv->driver.name = drv->name;
        drv->driver.bus = &zorro_bus_type;
-       drv->driver.probe = zorro_device_probe;
 
        /* register with core */
        count = driver_register(&drv->driver);
@@ -132,7 +131,8 @@ static int zorro_bus_match(struct device *dev, struct device_driver *drv)
 
 struct bus_type zorro_bus_type = {
        .name   = "zorro",
-       .match  = zorro_bus_match
+       .match  = zorro_bus_match,
+       .probe  = zorro_device_probe,
 };
 
 
index 55ccfa10ee9eeed3cf65f3efd855468b9125b88e..32a9f99154e23b30bb804ba6601b6f804c9baff5 100644 (file)
@@ -56,7 +56,7 @@ static inline int buf_check_overflow(struct cbuf *buf)
        return buf->p > buf->ep;
 }
 
-static inline int buf_check_size(struct cbuf *buf, int len)
+static int buf_check_size(struct cbuf *buf, int len)
 {
        if (buf->p + len > buf->ep) {
                if (buf->p < buf->ep) {
@@ -72,7 +72,7 @@ static inline int buf_check_size(struct cbuf *buf, int len)
        return 1;
 }
 
-static inline void *buf_alloc(struct cbuf *buf, int len)
+static void *buf_alloc(struct cbuf *buf, int len)
 {
        void *ret = NULL;
 
@@ -84,7 +84,7 @@ static inline void *buf_alloc(struct cbuf *buf, int len)
        return ret;
 }
 
-static inline void buf_put_int8(struct cbuf *buf, u8 val)
+static void buf_put_int8(struct cbuf *buf, u8 val)
 {
        if (buf_check_size(buf, 1)) {
                buf->p[0] = val;
@@ -92,7 +92,7 @@ static inline void buf_put_int8(struct cbuf *buf, u8 val)
        }
 }
 
-static inline void buf_put_int16(struct cbuf *buf, u16 val)
+static void buf_put_int16(struct cbuf *buf, u16 val)
 {
        if (buf_check_size(buf, 2)) {
                *(__le16 *) buf->p = cpu_to_le16(val);
@@ -100,7 +100,7 @@ static inline void buf_put_int16(struct cbuf *buf, u16 val)
        }
 }
 
-static inline void buf_put_int32(struct cbuf *buf, u32 val)
+static void buf_put_int32(struct cbuf *buf, u32 val)
 {
        if (buf_check_size(buf, 4)) {
                *(__le32 *)buf->p = cpu_to_le32(val);
@@ -108,7 +108,7 @@ static inline void buf_put_int32(struct cbuf *buf, u32 val)
        }
 }
 
-static inline void buf_put_int64(struct cbuf *buf, u64 val)
+static void buf_put_int64(struct cbuf *buf, u64 val)
 {
        if (buf_check_size(buf, 8)) {
                *(__le64 *)buf->p = cpu_to_le64(val);
@@ -116,7 +116,7 @@ static inline void buf_put_int64(struct cbuf *buf, u64 val)
        }
 }
 
-static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
+static void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
 {
        if (buf_check_size(buf, slen + 2)) {
                buf_put_int16(buf, slen);
@@ -130,7 +130,7 @@ static inline void buf_put_string(struct cbuf *buf, const char *s)
        buf_put_stringn(buf, s, strlen(s));
 }
 
-static inline u8 buf_get_int8(struct cbuf *buf)
+static u8 buf_get_int8(struct cbuf *buf)
 {
        u8 ret = 0;
 
@@ -142,7 +142,7 @@ static inline u8 buf_get_int8(struct cbuf *buf)
        return ret;
 }
 
-static inline u16 buf_get_int16(struct cbuf *buf)
+static u16 buf_get_int16(struct cbuf *buf)
 {
        u16 ret = 0;
 
@@ -154,7 +154,7 @@ static inline u16 buf_get_int16(struct cbuf *buf)
        return ret;
 }
 
-static inline u32 buf_get_int32(struct cbuf *buf)
+static u32 buf_get_int32(struct cbuf *buf)
 {
        u32 ret = 0;
 
@@ -166,7 +166,7 @@ static inline u32 buf_get_int32(struct cbuf *buf)
        return ret;
 }
 
-static inline u64 buf_get_int64(struct cbuf *buf)
+static u64 buf_get_int64(struct cbuf *buf)
 {
        u64 ret = 0;
 
@@ -178,7 +178,7 @@ static inline u64 buf_get_int64(struct cbuf *buf)
        return ret;
 }
 
-static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
+static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
 {
        vstr->len = buf_get_int16(buf);
        if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
@@ -190,7 +190,7 @@ static inline void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
        }
 }
 
-static inline void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
+static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
 {
        qid->type = buf_get_int8(bufp);
        qid->version = buf_get_int32(bufp);
@@ -254,7 +254,7 @@ static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
  *
  */
 
-static inline void
+static void
 buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
 {
        stat->size = buf_get_int16(bufp);
@@ -427,7 +427,7 @@ static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
        buf_put_int64(bufp, val);
 }
 
-static inline void
+static void
 v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
 {
        if (data) {
@@ -441,7 +441,7 @@ v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
        buf_put_stringn(bufp, data, str->len);
 }
 
-static inline int
+static int
 v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
                   unsigned char **pdata)
 {
index e93a7ae467c996644a189d5b73d4d538459dd758..62d8d4acb8bbbe75ba0965214808c259c4b1b292 100644 (file)
@@ -195,6 +195,8 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
                if (!empty)
                        d_invalidate(dentry);
 
+               nd.dentry = dentry;
+               nd.mnt = mnt;
                nd.flags = LOOKUP_DIRECTORY;
                status = (dentry->d_op->d_revalidate)(dentry, &nd);
 
index f979ebbce49c99ec000b65cc2f4d1728c6c79639..1b117a441298048b29fc8f4c405d0bfb864852ae 100644 (file)
@@ -1218,7 +1218,7 @@ static int writenote(struct memelfnote *men, struct file *file)
        if (!dump_seek(file, (off))) \
                goto end_coredump;
 
-static inline void fill_elf_header(struct elfhdr *elf, int segs)
+static void fill_elf_header(struct elfhdr *elf, int segs)
 {
        memcpy(elf->e_ident, ELFMAG, SELFMAG);
        elf->e_ident[EI_CLASS] = ELF_CLASS;
@@ -1243,7 +1243,7 @@ static inline void fill_elf_header(struct elfhdr *elf, int segs)
        return;
 }
 
-static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+static void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
 {
        phdr->p_type = PT_NOTE;
        phdr->p_offset = offset;
index 9ccc7d8275b8ec451c78b66dd777e65b663852d3..6a7b730c206bbc8c8e0f757187873dff2af3d3b6 100644 (file)
@@ -264,7 +264,7 @@ static int unquote(char *from)
        return p - from;
 }
 
-static inline char * check_special_flags (char * sfs, Node * e)
+static char * check_special_flags (char * sfs, Node * e)
 {
        char * p = sfs;
        int cont = 1;
index 7b30695899511ca64404f8061a9d1563573db44c..bbc442b8c86722dbe69651fb593bfe7d3f6c936c 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -123,7 +123,7 @@ static void bio_fs_destructor(struct bio *bio)
        bio_free(bio, fs_bio_set);
 }
 
-inline void bio_init(struct bio *bio)
+void bio_init(struct bio *bio)
 {
        bio->bi_next = NULL;
        bio->bi_bdev = NULL;
@@ -253,7 +253,7 @@ inline int bio_hw_segments(request_queue_t *q, struct bio *bio)
  *     the actual data it points to. Reference count of returned
  *     bio will be one.
  */
-inline void __bio_clone(struct bio *bio, struct bio *bio_src)
+void __bio_clone(struct bio *bio, struct bio *bio_src)
 {
        request_queue_t *q = bdev_get_queue(bio_src->bi_bdev);
 
index b9bb7ad6897b90456332813bc15615741171c9c8..7cdf48a9a50105c4a074d53f807077c398f4fdb5 100644 (file)
@@ -1165,7 +1165,7 @@ failed:
  * some of those buffers may be aliases of filesystem data.
  * grow_dev_page() will go BUG() if this happens.
  */
-static inline int
+static int
 grow_buffers(struct block_device *bdev, sector_t block, int size)
 {
        struct page *page;
@@ -1391,7 +1391,7 @@ static void bh_lru_install(struct buffer_head *bh)
 /*
  * Look up the bh in this cpu's LRU.  If it's there, move it to the head.
  */
-static inline struct buffer_head *
+static struct buffer_head *
 lookup_bh_lru(struct block_device *bdev, sector_t block, int size)
 {
        struct buffer_head *ret = NULL;
@@ -1541,7 +1541,7 @@ EXPORT_SYMBOL(set_bh_page);
 /*
  * Called when truncating a buffer on a page completely.
  */
-static inline void discard_buffer(struct buffer_head * bh)
+static void discard_buffer(struct buffer_head * bh)
 {
        lock_buffer(bh);
        clear_buffer_dirty(bh);
index 3b1b1eefdbb01686f127df582143f922bf87c193..21195c481637658ad4e676ba35c204da83d53d57 100644 (file)
@@ -35,7 +35,7 @@ static struct char_device_struct {
        unsigned int major;
        unsigned int baseminor;
        int minorct;
-       const char *name;
+       char name[64];
        struct file_operations *fops;
        struct cdev *cdev;              /* will die */
 } *chrdevs[MAX_PROBE_HASH];
@@ -46,34 +46,84 @@ static inline int major_to_index(int major)
        return major % MAX_PROBE_HASH;
 }
 
-/* get char device names in somewhat random order */
-int get_chrdev_list(char *page)
-{
+struct chrdev_info {
+       int index;
        struct char_device_struct *cd;
-       int i, len;
+};
 
-       len = sprintf(page, "Character devices:\n");
+void *get_next_chrdev(void *dev)
+{
+       struct chrdev_info *info;
 
+       if (dev == NULL) {
+               info = kmalloc(sizeof(*info), GFP_KERNEL);
+               if (!info)
+                       goto out;
+               info->index=0;
+               info->cd = chrdevs[info->index];
+               if (info->cd)
+                       goto out;
+       } else {
+               info = dev;
+       }
+
+       while (info->index < ARRAY_SIZE(chrdevs)) {
+               if (info->cd)
+                       info->cd = info->cd->next;
+               if (info->cd)
+                       goto out;
+               /*
+                * No devices on this chain, move to the next
+                */
+               info->index++;
+               info->cd = (info->index < ARRAY_SIZE(chrdevs)) ?
+                       chrdevs[info->index] : NULL;
+               if (info->cd)
+                       goto out;
+       }
+
+out:
+       return info;
+}
+
+void *acquire_chrdev_list(void)
+{
        down(&chrdevs_lock);
+       return get_next_chrdev(NULL);
+}
+
+void release_chrdev_list(void *dev)
+{
+       up(&chrdevs_lock);
+       kfree(dev);
+}
+
+
+int count_chrdev_list(void)
+{
+       struct char_device_struct *cd;
+       int i, count;
+
+       count = 0;
+
        for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
-               for (cd = chrdevs[i]; cd; cd = cd->next) {
-                       /*
-                        * if the current name, plus the 5 extra characters
-                        * in the device line for this entry
-                        * would run us off the page, we're done
-                        */
-                       if ((len+strlen(cd->name) + 5) >= PAGE_SIZE)
-                               goto page_full;
-
-
-                       len += sprintf(page+len, "%3d %s\n",
-                                      cd->major, cd->name);
-               }
+               for (cd = chrdevs[i]; cd; cd = cd->next)
+                       count++;
        }
-page_full:
-       up(&chrdevs_lock);
 
-       return len;
+       return count;
+}
+
+int get_chrdev_info(void *dev, int *major, char **name)
+{
+       struct chrdev_info *info = dev;
+
+       if (info->cd == NULL)
+               return 1;
+
+       *major = info->cd->major;
+       *name = info->cd->name;
+       return 0;
 }
 
 /*
@@ -121,7 +171,7 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
        cd->major = major;
        cd->baseminor = baseminor;
        cd->minorct = minorct;
-       cd->name = name;
+       strncpy(cd->name,name, 64);
 
        i = major_to_index(major);
 
index 271b75d1597f507bacbd78b7be31227d5492dd2e..2468ac1df2f04cf5cfc1bde19b4924c9f135ce09 100644 (file)
@@ -1537,7 +1537,7 @@ out_ret:
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
  * 64-bit unsigned longs.
  */
-static inline
+static
 int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
                        unsigned long *fdset)
 {
@@ -1570,7 +1570,7 @@ int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
        return 0;
 }
 
-static inline
+static
 void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
                        unsigned long *fdset)
 {
index 134d6775183f80b393317b5fa9d691fce7eb2fa1..86bdb93789c6629c60027fdba100e99aa2709610 100644 (file)
@@ -94,7 +94,7 @@ static void d_free(struct dentry *dentry)
  * d_iput() operation if defined.
  * Called with dcache_lock and per dentry lock held, drops both.
  */
-static inline void dentry_iput(struct dentry * dentry)
+static void dentry_iput(struct dentry * dentry)
 {
        struct inode *inode = dentry->d_inode;
        if (inode) {
index b5bcf1aae0abe61a6d7524b2614bcda7c78e18da..62b40af68cc4e40da9c749ce36bef9816894a003 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -575,7 +575,7 @@ static int exec_mmap(struct mm_struct *mm)
  * disturbing other processes.  (Other processes might share the signal
  * table via the CLONE_SIGHAND option to clone().)
  */
-static inline int de_thread(struct task_struct *tsk)
+static int de_thread(struct task_struct *tsk)
 {
        struct signal_struct *sig = tsk->signal;
        struct sighand_struct *newsighand, *oldsighand = tsk->sighand;
@@ -780,7 +780,7 @@ no_thread_group:
  * so that a new one can be started
  */
 
-static inline void flush_old_files(struct files_struct * files)
+static void flush_old_files(struct files_struct * files)
 {
        long j = -1;
        struct fdtable *fdt;
@@ -964,7 +964,7 @@ int prepare_binprm(struct linux_binprm *bprm)
 
 EXPORT_SYMBOL(prepare_binprm);
 
-static inline int unsafe_exec(struct task_struct *p)
+static int unsafe_exec(struct task_struct *p)
 {
        int unsafe = 0;
        if (p->ptrace & PT_PTRACED) {
index c5513953c825daccbfbfae119e71bec81dec63c0..ad1432a2a62ee85eeef7bfaea49d142c1161af08 100644 (file)
@@ -83,10 +83,7 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str
                if (!inode)
                        return ERR_PTR(-EACCES);
        }
-       if (inode)
-               return d_splice_alias(inode, dentry);
-       d_add(dentry, inode);
-       return NULL;
+       return d_splice_alias(inode, dentry);
 }
 
 struct dentry *ext2_get_parent(struct dentry *child)
index af193a304ee5868c6bd54db9f8018159940463bb..8bd8ac0777046e39c466fae28cec573140e72c29 100644 (file)
@@ -1005,10 +1005,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
                if (!inode)
                        return ERR_PTR(-EACCES);
        }
-       if (inode)
-               return d_splice_alias(inode, dentry);
-       d_add(dentry, inode);
-       return NULL;
+       return d_splice_alias(inode, dentry);
 }
 
 
index d0767fe5836247dd68aac8d7f3bd5818984e2790..5f96786d1c73dc6c9ac27565b521835f6fe5ff12 100644 (file)
@@ -36,7 +36,7 @@ void fastcall set_close_on_exec(unsigned int fd, int flag)
        spin_unlock(&files->file_lock);
 }
 
-static inline int get_close_on_exec(unsigned int fd)
+static int get_close_on_exec(unsigned int fd)
 {
        struct files_struct *files = current->files;
        struct fdtable *fdt;
index ab4c3a9d51b88948650d345378934fe912c8c440..f568102da1e8df3be5126e91a50914d55dc5c0bb 100644 (file)
@@ -402,7 +402,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
                inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                info = HUGETLBFS_I(inode);
-               mpol_shared_policy_init(&info->policy);
+               mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL);
                switch (mode & S_IFMT) {
                default:
                        init_special_inode(inode, mode, dev);
index e37e82b7cbf0127281fb12deca7475810906674a..e7ba0c30e0711ff16669c1ec6e0e8cee20be7f74 100644 (file)
@@ -185,8 +185,5 @@ struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct n
                }
        }
        unlock_kernel();
-       if (inode)
-               return d_splice_alias(inode, dentry);
-       d_add(dentry, inode);
-       return NULL;
+       return d_splice_alias(inode, dentry);
 }
index fff108bb118b14db6a4ca927b62320a4cf4f2b19..70f7a896c04ad8cac6389646aad49ad44e1da2a5 100644 (file)
@@ -47,7 +47,7 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
             ic = next_inode(&i, ic, (c)))
 
 
-static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
+static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
                                        struct jffs2_inode_cache *ic)
 {
        struct jffs2_full_dirent *fd;
index c79eebb8ab32caeeb0f3527ed54af5e37c8eff89..b635e167a3faf721763e1605265a634606bb67fd 100644 (file)
@@ -134,7 +134,7 @@ static void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_
 /*
  * Allocate and initializes a new fragment.
  */
-static inline struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
+static struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
 {
        struct jffs2_node_frag *newfrag;
 
@@ -513,7 +513,7 @@ free_out:
  *
  * Checks the node if we are in the checking stage.
  */
-static inline int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
+static int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
 {
        int ret;
 
index f01e9c0d2677062e8db1dcbb22ecac814ab44de7..200fbda2c6d152368f08c742ed2db4dacf12b65a 100644 (file)
@@ -44,7 +44,7 @@ loff_t_to_s32(loff_t offset)
 /*
  * XDR functions for basic NLM types
  */
-static inline u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
+static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
 {
        unsigned int    len;
 
@@ -79,7 +79,7 @@ nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
        return p;
 }
 
-static inline u32 *
+static u32 *
 nlm_decode_fh(u32 *p, struct nfs_fh *f)
 {
        unsigned int    len;
@@ -119,7 +119,7 @@ nlm_encode_oh(u32 *p, struct xdr_netobj *oh)
        return xdr_encode_netobj(p, oh);
 }
 
-static inline u32 *
+static u32 *
 nlm_decode_lock(u32 *p, struct nlm_lock *lock)
 {
        struct file_lock        *fl = &lock->fl;
index 0f1e4530670f18567cc788b39af3ebbced8388ed..f5bbe4c97c5800b1ea0b2c342c0352747deed074 100644 (file)
@@ -126,7 +126,7 @@ __mb_cache_entry_is_hashed(struct mb_cache_entry *ce)
 }
 
 
-static inline void
+static void
 __mb_cache_entry_unhash(struct mb_cache_entry *ce)
 {
        int n;
@@ -139,7 +139,7 @@ __mb_cache_entry_unhash(struct mb_cache_entry *ce)
 }
 
 
-static inline void
+static void
 __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask)
 {
        struct mb_cache *cache = ce->e_cache;
@@ -158,7 +158,7 @@ __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask)
 }
 
 
-static inline void
+static void
 __mb_cache_entry_release_unlock(struct mb_cache_entry *ce)
 {
        /* Wake up all processes queuing for this cache entry. */
index 1e5746eb13809777ca97c5cb4db2fc778008c30c..33fb5bd34a8111c73768cfac883fd4ea49ea07b8 100644 (file)
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-static inline int do_getname(const char __user *filename, char *page)
+static int do_getname(const char __user *filename, char *page)
 {
        int retval;
        unsigned long len = PATH_MAX;
@@ -396,7 +396,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name,
  * short-cut DAC fails, then call permission() to do more
  * complete permission check.
  */
-static inline int exec_permission_lite(struct inode *inode,
+static int exec_permission_lite(struct inode *inode,
                                       struct nameidata *nd)
 {
        umode_t mode = inode->i_mode;
@@ -486,7 +486,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
 static int __emul_lookup_dentry(const char *, struct nameidata *);
 
 /* SMP-safe */
-static inline int
+static __always_inline int
 walk_init_root(const char *name, struct nameidata *nd)
 {
        read_lock(&current->fs->lock);
@@ -504,7 +504,7 @@ walk_init_root(const char *name, struct nameidata *nd)
        return 1;
 }
 
-static inline int __vfs_follow_link(struct nameidata *nd, const char *link)
+static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
 {
        int res = 0;
        char *name;
@@ -544,7 +544,7 @@ struct path {
        struct dentry *dentry;
 };
 
-static inline int __do_follow_link(struct path *path, struct nameidata *nd)
+static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd)
 {
        int error;
        void *cookie;
@@ -690,7 +690,7 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
        return 0;
 }
 
-static inline void follow_dotdot(struct nameidata *nd)
+static __always_inline void follow_dotdot(struct nameidata *nd)
 {
        while(1) {
                struct vfsmount *parent;
@@ -1294,7 +1294,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
  * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
-static inline int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 {
        int error;
 
@@ -2315,7 +2315,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        return error;
 }
 
-static inline int do_rename(const char * oldname, const char * newname)
+static int do_rename(const char * oldname, const char * newname)
 {
        int error = 0;
        struct dentry * old_dir, * new_dir;
index 8c8839203cd5a0bae7e0e4cb0fec352748b02391..d277a58bd128c34926eb7f21c492c621333b770e 100644 (file)
@@ -716,10 +716,8 @@ static void ncp_put_super(struct super_block *sb)
        fput(server->ncp_filp);
        kill_proc(server->m.wdog_pid, SIGTERM, 1);
 
-       if (server->priv.data) 
-               ncp_kfree_s(server->priv.data, server->priv.len);
-       if (server->auth.object_name)
-               ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
+       kfree(server->priv.data);
+       kfree(server->auth.object_name);
        vfree(server->packet);
        sb->s_fs_info = NULL;
        kfree(server);
@@ -958,11 +956,6 @@ out:
        return result;
 }
 
-#ifdef DEBUG_NCP_MALLOC
-int ncp_malloced;
-int ncp_current_malloced;
-#endif
-
 static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
@@ -981,10 +974,6 @@ static int __init init_ncp_fs(void)
        int err;
        DPRINTK("ncpfs: init_module called\n");
 
-#ifdef DEBUG_NCP_MALLOC
-       ncp_malloced = 0;
-       ncp_current_malloced = 0;
-#endif
        err = init_inodecache();
        if (err)
                goto out1;
@@ -1003,10 +992,6 @@ static void __exit exit_ncp_fs(void)
        DPRINTK("ncpfs: cleanup_module called\n");
        unregister_filesystem(&ncp_fs_type);
        destroy_inodecache();
-#ifdef DEBUG_NCP_MALLOC
-       PRINTK("ncp_malloced: %d\n", ncp_malloced);
-       PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
-#endif
 }
 
 module_init(init_ncp_fs)
index d6e0c089e1b110830b0e596160867f4c3bd93856..eb3813ad136f192e5c0a7551eefc8cd417d09fb3 100644 (file)
@@ -518,10 +518,11 @@ outrel:
                        if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
                                return -ENOMEM;
                        if (user.object_name_len) {
-                               newname = ncp_kmalloc(user.object_name_len, GFP_USER);
-                               if (!newname) return -ENOMEM;
+                               newname = kmalloc(user.object_name_len, GFP_USER);
+                               if (!newname)
+                                       return -ENOMEM;
                                if (copy_from_user(newname, user.object_name, user.object_name_len)) {
-                                       ncp_kfree_s(newname, user.object_name_len);
+                                       kfree(newname);
                                        return -EFAULT;
                                }
                        } else {
@@ -540,8 +541,8 @@ outrel:
                        server->priv.len = 0;
                        server->priv.data = NULL;
                        /* leave critical section */
-                       if (oldprivate) ncp_kfree_s(oldprivate, oldprivatelen);
-                       if (oldname) ncp_kfree_s(oldname, oldnamelen);
+                       kfree(oldprivate);
+                       kfree(oldname);
                        return 0;
                }
        case NCP_IOC_GETPRIVATEDATA:
@@ -581,10 +582,11 @@ outrel:
                        if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
                                return -ENOMEM;
                        if (user.len) {
-                               new = ncp_kmalloc(user.len, GFP_USER);
-                               if (!new) return -ENOMEM;
+                               new = kmalloc(user.len, GFP_USER);
+                               if (!new)
+                                       return -ENOMEM;
                                if (copy_from_user(new, user.data, user.len)) {
-                                       ncp_kfree_s(new, user.len);
+                                       kfree(new);
                                        return -EFAULT;
                                }
                        } else {
@@ -596,7 +598,7 @@ outrel:
                        server->priv.len = user.len;
                        server->priv.data = new;
                        /* leave critical section */
-                       if (old) ncp_kfree_s(old, oldlen);
+                       kfree(old);
                        return 0;
                }
 
index aa7bb41b293d2bf906980cdfadcd152ec0d15271..e3a0797dd56ba16ef65fb2df1c348f4ae7e806e2 100644 (file)
@@ -37,7 +37,7 @@ static u32    nfs_ftypes[] = {
 /*
  * XDR functions for basic NFS types
  */
-static inline u32 *
+static u32 *
 decode_fh(u32 *p, struct svc_fh *fhp)
 {
        fh_init(fhp, NFS_FHSIZE);
@@ -151,7 +151,7 @@ decode_sattr(u32 *p, struct iattr *iap)
        return p;
 }
 
-static inline u32 *
+static u32 *
 encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
             struct kstat *stat)
 {
index eef0f29e86ef3de20913fef86bd9412c3751e898..d722579df79a679314750e9adf0be617a5729887 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -50,7 +50,7 @@ void pipe_wait(struct inode * inode)
        mutex_lock(PIPE_MUTEX(*inode));
 }
 
-static inline int
+static int
 pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len)
 {
        unsigned long copy;
@@ -70,7 +70,7 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len)
        return 0;
 }
 
-static inline int
+static int
 pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len)
 {
        unsigned long copy;
index fb117b74809eca5169b8805a1c83437cd5033105..9bdd077d6f55a020f06e43d93a5f7540b214b523 100644 (file)
@@ -81,6 +81,30 @@ void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop
        __proc_device_tree_add_prop(pde, prop);
 }
 
+void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
+                                 struct property *prop)
+{
+       remove_proc_entry(prop->name, pde);
+}
+
+void proc_device_tree_update_prop(struct proc_dir_entry *pde,
+                                 struct property *newprop,
+                                 struct property *oldprop)
+{
+       struct proc_dir_entry *ent;
+
+       for (ent = pde->subdir; ent != NULL; ent = ent->next)
+               if (ent->data == oldprop)
+                       break;
+       if (ent == NULL) {
+               printk(KERN_WARNING "device-tree: property \"%s\" "
+                      " does not exist\n", oldprop->name);
+       } else {
+               ent->data = newprop;
+               ent->size = newprop->length;
+       }
+}
+
 /*
  * Process a node, adding entries for its children and its properties.
  */
index 63bf6c00fa0ccc736a2aada6e2c93d9a1e806abe..8f8014285a349c14f547c8e3d92d47cc9a6ff4b7 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/time.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
+#include <linux/fs.h>
 #include <linux/tty.h>
 #include <linux/string.h>
 #include <linux/mman.h>
@@ -62,7 +63,6 @@
  */
 extern int get_hardware_list(char *);
 extern int get_stram_list(char *);
-extern int get_chrdev_list(char *);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_dma_list(char *);
@@ -248,6 +248,154 @@ static int cpuinfo_open(struct inode *inode, struct file *file)
 {
        return seq_open(file, &cpuinfo_op);
 }
+
+enum devinfo_states {
+       CHR_HDR,
+       CHR_LIST,
+       BLK_HDR,
+       BLK_LIST,
+       DEVINFO_DONE
+};
+
+struct devinfo_state {
+       void *chrdev;
+       void *blkdev;
+       unsigned int num_records;
+       unsigned int cur_record;
+       enum devinfo_states state;
+};
+
+static void *devinfo_start(struct seq_file *f, loff_t *pos)
+{
+       struct devinfo_state *info = f->private;
+
+       if (*pos) {
+               if ((info) && (*pos <= info->num_records))
+                       return info;
+               return NULL;
+       }
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       f->private = info;
+       info->chrdev = acquire_chrdev_list();
+       info->blkdev = acquire_blkdev_list();
+       info->state = CHR_HDR;
+       info->num_records = count_chrdev_list();
+       info->num_records += count_blkdev_list();
+       info->num_records += 2; /* Character and Block headers */
+       *pos = 1;
+       info->cur_record = *pos;
+       return info;
+}
+
+static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos)
+{
+       int idummy;
+       char *ndummy;
+       struct devinfo_state *info = f->private;
+
+       switch (info->state) {
+               case CHR_HDR:
+                       info->state = CHR_LIST;
+                       (*pos)++;
+                       /*fallthrough*/
+               case CHR_LIST:
+                       if (get_chrdev_info(info->chrdev,&idummy,&ndummy)) {
+                               /*
+                                * The character dev list is complete
+                                */
+                               info->state = BLK_HDR;
+                       } else {
+                               info->chrdev = get_next_chrdev(info->chrdev);
+                       }
+                       (*pos)++;
+                       break;
+               case BLK_HDR:
+                       info->state = BLK_LIST;
+                       (*pos)++;
+                       break;
+               case BLK_LIST:
+                       if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) {
+                               /*
+                                * The block dev list is complete
+                                */
+                               info->state = DEVINFO_DONE;
+                       } else {
+                               info->blkdev = get_next_blkdev(info->blkdev);
+                       }
+                       (*pos)++;
+                       break;
+               case DEVINFO_DONE:
+                       (*pos)++;
+                       info->cur_record = *pos;
+                       info = NULL;
+                       break;
+               default:
+                       break;
+       }
+       if (info)
+               info->cur_record = *pos;
+       return info;
+}
+
+static void devinfo_stop(struct seq_file *f, void *v)
+{
+       struct devinfo_state *info = f->private;
+
+       if (info) {
+               release_chrdev_list(info->chrdev);
+               release_blkdev_list(info->blkdev);
+               f->private = NULL;
+               kfree(info);
+       }
+}
+
+static int devinfo_show(struct seq_file *f, void *arg)
+{
+       int major;
+       char *name;
+       struct devinfo_state *info = f->private;
+
+       switch(info->state) {
+               case CHR_HDR:
+                       seq_printf(f,"Character devices:\n");
+                       /* fallthrough */
+               case CHR_LIST:
+                       if (!get_chrdev_info(info->chrdev,&major,&name))
+                               seq_printf(f,"%3d %s\n",major,name);
+                       break;
+               case BLK_HDR:
+                       seq_printf(f,"\nBlock devices:\n");
+                       /* fallthrough */
+               case BLK_LIST:
+                       if (!get_blkdev_info(info->blkdev,&major,&name))
+                               seq_printf(f,"%3d %s\n",major,name);
+                       break;
+               default:
+                       break;
+       }
+
+       return 0;
+}
+
+static  struct seq_operations devinfo_op = {
+       .start  = devinfo_start,
+       .next   = devinfo_next,
+       .stop   = devinfo_stop,
+       .show   = devinfo_show,
+};
+
+static int devinfo_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &devinfo_op);
+}
+
+static struct file_operations proc_devinfo_operations = {
+       .open           = devinfo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
 static struct file_operations proc_cpuinfo_operations = {
        .open           = cpuinfo_open,
        .read           = seq_read,
@@ -450,14 +598,6 @@ static struct file_operations proc_stat_operations = {
        .release        = single_release,
 };
 
-static int devices_read_proc(char *page, char **start, off_t off,
-                                int count, int *eof, void *data)
-{
-       int len = get_chrdev_list(page);
-       len += get_blkdev_list(page+len, len);
-       return proc_calc_metrics(page, start, off, count, eof, len);
-}
-
 /*
  * /proc/interrupts
  */
@@ -582,7 +722,6 @@ void __init proc_misc_init(void)
 #ifdef CONFIG_STRAM_PROC
                {"stram",       stram_read_proc},
 #endif
-               {"devices",     devices_read_proc},
                {"filesystems", filesystems_read_proc},
                {"cmdline",     cmdline_read_proc},
                {"locks",       locks_read_proc},
@@ -598,6 +737,7 @@ void __init proc_misc_init(void)
        entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
        if (entry)
                entry->proc_fops = &proc_kmsg_operations;
+       create_seq_entry("devices", 0, &proc_devinfo_operations);
        create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
        create_seq_entry("partitions", 0, &proc_partitions_operations);
        create_seq_entry("stat", 0, &proc_stat_operations);
index 7afcbb1b93761a539ddb8d31f4448b122f6f5e6b..a4ef91bb4f3b9afe61628d52a7bb3e08356b42da 100644 (file)
@@ -35,7 +35,8 @@ static int v2_check_quota_file(struct super_block *sb, int type)
  
        size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
        if (size != sizeof(struct v2_disk_dqheader)) {
-               printk("failed read\n");
+               printk("quota_v2: failed read expected=%d got=%d\n",
+                       sizeof(struct v2_disk_dqheader), size);
                return 0;
        }
        if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
index 3549067c42d941546f4fa12ad266612a9f9f4413..8f8d8d01107c880975c4d2d2de465be7a3041018 100644 (file)
@@ -375,11 +375,7 @@ static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
                return ERR_PTR(-EIO);
        }
 
-       if (inode)
-               return d_splice_alias(inode, dentry);
-
-       d_add(dentry, inode);
-       return NULL;
+       return d_splice_alias(inode, dentry);
 }
 
 /* 
index 93246b7dd6fb46ebc47d47f681b0275bf441de23..6673ee82cb4c09667ed06805a1505870c156220e 100644 (file)
@@ -13,7 +13,6 @@ smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \
 EXTRA_CFLAGS += -DSMBFS_PARANOIA
 #EXTRA_CFLAGS += -DSMBFS_DEBUG
 #EXTRA_CFLAGS += -DSMBFS_DEBUG_VERBOSE
-#EXTRA_CFLAGS += -DDEBUG_SMB_MALLOC
 #EXTRA_CFLAGS += -DDEBUG_SMB_TIMESTAMP
 #EXTRA_CFLAGS += -Werror
 
index 6ec88bf59b2def7aa402d060c0fd84dc770741a6..02e3e82d465c5ff28f906f0c3fcd081a5654e66c 100644 (file)
@@ -487,11 +487,11 @@ smb_put_super(struct super_block *sb)
        if (server->conn_pid)
                kill_proc(server->conn_pid, SIGTERM, 1);
 
-       smb_kfree(server->ops);
+       kfree(server->ops);
        smb_unload_nls(server);
        sb->s_fs_info = NULL;
        smb_unlock_server(server);
-       smb_kfree(server);
+       kfree(server);
 }
 
 static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
@@ -519,11 +519,10 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
        sb->s_op = &smb_sops;
        sb->s_time_gran = 100;
 
-       server = smb_kmalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
+       server = kzalloc(sizeof(struct smb_sb_info), GFP_KERNEL);
        if (!server)
                goto out_no_server;
        sb->s_fs_info = server;
-       memset(server, 0, sizeof(struct smb_sb_info));
 
        server->super_block = sb;
        server->mnt = NULL;
@@ -542,8 +541,8 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
        /* FIXME: move these to the smb_sb_info struct */
        VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) +
                sizeof(struct smb_mount_data_kernel));
-       mem = smb_kmalloc(sizeof(struct smb_ops) +
-                         sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
+       mem = kmalloc(sizeof(struct smb_ops) +
+                     sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
        if (!mem)
                goto out_no_mem;
 
@@ -621,12 +620,12 @@ out_no_root:
 out_no_smbiod:
        smb_unload_nls(server);
 out_bad_option:
-       smb_kfree(mem);
+       kfree(mem);
 out_no_mem:
        if (!server->mnt)
                printk(KERN_ERR "smb_fill_super: allocation failure\n");
        sb->s_fs_info = NULL;
-       smb_kfree(server);
+       kfree(server);
        goto out_fail;
 out_wrong_data:
        printk(KERN_ERR "smbfs: mount_data version %d is not supported\n", ver);
@@ -782,12 +781,6 @@ out:
        return error;
 }
 
-#ifdef DEBUG_SMB_MALLOC
-int smb_malloced;
-int smb_current_kmalloced;
-int smb_current_vmalloced;
-#endif
-
 static struct super_block *smb_get_sb(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data)
 {
@@ -807,12 +800,6 @@ static int __init init_smb_fs(void)
        int err;
        DEBUG1("registering ...\n");
 
-#ifdef DEBUG_SMB_MALLOC
-       smb_malloced = 0;
-       smb_current_kmalloced = 0;
-       smb_current_vmalloced = 0;
-#endif
-
        err = init_inodecache();
        if (err)
                goto out_inode;
@@ -837,11 +824,6 @@ static void __exit exit_smb_fs(void)
        unregister_filesystem(&smb_fs_type);
        smb_destroy_request_cache();
        destroy_inodecache();
-#ifdef DEBUG_SMB_MALLOC
-       printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
-       printk(KERN_DEBUG "smb_current_kmalloced: %d\n",smb_current_kmalloced);
-       printk(KERN_DEBUG "smb_current_vmalloced: %d\n",smb_current_vmalloced);
-#endif
 }
 
 module_init(init_smb_fs)
index a0f296d9928ad39d1044597553c36f9c75ac0b55..c71c375863cc473a254462d8187365cecb302367 100644 (file)
@@ -68,7 +68,7 @@ static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server,
                goto out;
 
        if (bufsize > 0) {
-               buf = smb_kmalloc(bufsize, GFP_NOFS);
+               buf = kmalloc(bufsize, GFP_NOFS);
                if (!buf) {
                        kmem_cache_free(req_cachep, req);
                        return NULL;
@@ -124,9 +124,8 @@ static void smb_free_request(struct smb_request *req)
 {
        atomic_dec(&req->rq_server->nr_requests);
        if (req->rq_buffer && !(req->rq_flags & SMB_REQ_STATIC))
-               smb_kfree(req->rq_buffer);
-       if (req->rq_trans2buffer)
-               smb_kfree(req->rq_trans2buffer);
+               kfree(req->rq_buffer);
+       kfree(req->rq_trans2buffer);
        kmem_cache_free(req_cachep, req);
 }
 
@@ -183,8 +182,7 @@ static int smb_setup_request(struct smb_request *req)
        req->rq_err = 0;
        req->rq_errno = 0;
        req->rq_fragment = 0;
-       if (req->rq_trans2buffer)
-               smb_kfree(req->rq_trans2buffer);
+       kfree(req->rq_trans2buffer);
 
        return 0;
 }
@@ -647,10 +645,9 @@ static int smb_recv_trans2(struct smb_sb_info *server, struct smb_request *req)
                        goto out_too_long;
 
                req->rq_trans2bufsize = buf_len;
-               req->rq_trans2buffer = smb_kmalloc(buf_len, GFP_NOFS);
+               req->rq_trans2buffer = kzalloc(buf_len, GFP_NOFS);
                if (!req->rq_trans2buffer)
                        goto out_no_mem;
-               memset(req->rq_trans2buffer, 0, buf_len);
 
                req->rq_parm = req->rq_trans2buffer;
                req->rq_data = req->rq_trans2buffer + parm_tot;
index a9f4421ddb6f6e4b93975c72eb234039f48bd91a..3ada9dcf55b8bd86046a95812d6ad918b9a00f2f 100644 (file)
@@ -49,7 +49,7 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        
        UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
        
@@ -81,8 +81,9 @@ void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count
        for (i = bit; i < end_bit; i++) {
                if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i))
                        ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i);
-               else ufs_error (sb, "ufs_free_fragments",
-                       "bit already cleared for fragment %u", i);
+               else 
+                       ufs_error (sb, "ufs_free_fragments",
+                                  "bit already cleared for fragment %u", i);
        }
        
        DQUOT_FREE_BLOCK (inode, count);
@@ -143,7 +144,7 @@ void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) {
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
 
        UFSD(("ENTER, fragment %u, count %u\n", fragment, count))
        
@@ -247,7 +248,7 @@ unsigned ufs_new_fragments (struct inode * inode, __fs32 * p, unsigned fragment,
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        *err = -ENOSPC;
 
        lock_super (sb);
@@ -407,7 +408,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment,
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first (USPI_UBH);
+       usb1 = ubh_get_usb_first (uspi);
        count = newcount - oldcount;
        
        cgno = ufs_dtog(fragment);
@@ -490,7 +491,7 @@ static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        oldcg = cgno;
        
        /*
@@ -606,7 +607,7 @@ static unsigned ufs_alloccg_block (struct inode * inode,
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        ucg = ubh_get_ucg(UCPI_UBH);
 
        if (goal == 0) {
@@ -663,7 +664,7 @@ static unsigned ufs_bitmap_search (struct super_block * sb,
        UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
 
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first (USPI_UBH);
+       usb1 = ubh_get_usb_first (uspi);
        ucg = ubh_get_ucg(UCPI_UBH);
 
        if (goal)
index 0938945b9cbc2c628750061a05f772ebeee670e5..c7a47ed4f430d28ab0613b1d8b3986f79e0b528a 100644 (file)
@@ -72,7 +72,7 @@ void ufs_free_inode (struct inode * inode)
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        
        ino = inode->i_ino;
 
@@ -167,7 +167,7 @@ struct inode * ufs_new_inode(struct inode * dir, int mode)
        ufsi = UFS_I(inode);
        sbi = UFS_SB(sb);
        uspi = sbi->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
 
        lock_super (sb);
 
index 55f4aa16e3fc930259964fabbb0dce8c905fccbb..e0c04e36a0518a42548d4b4aad82743f7572bb82 100644 (file)
@@ -61,7 +61,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off
        int n = 0;
 
 
-       UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%d \n",ptrs,double_blocks));
+       UFSD(("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks));
        if (i_block < 0) {
                ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0");
        } else if (i_block < direct_blocks) {
@@ -104,7 +104,7 @@ u64  ufs_frag_map(struct inode *inode, sector_t frag)
        unsigned flags = UFS_SB(sb)->s_flags;
        u64 temp = 0L;
 
-       UFSD((": frag = %lu  depth = %d\n",frag,depth));
+       UFSD((": frag = %llu  depth = %d\n", (unsigned long long)frag, depth));
        UFSD((": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",uspi->s_fpbshift,uspi->s_apbmask,mask));
 
        if (depth == 0)
@@ -365,9 +365,10 @@ repeat:
                sync_dirty_buffer(bh);
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
+       UFSD(("result %u\n", tmp + blockoff));
 out:
        brelse (bh);
-       UFSD(("EXIT, result %u\n", tmp + blockoff))
+       UFSD(("EXIT\n"));
        return result;
 }
 
@@ -386,7 +387,7 @@ static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buf
        
        if (!create) {
                phys64 = ufs_frag_map(inode, fragment);
-               UFSD(("phys64 = %lu \n",phys64));
+               UFSD(("phys64 = %llu \n",phys64));
                if (phys64)
                        map_bh(bh_result, sb, phys64);
                return 0;
@@ -401,7 +402,7 @@ static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buf
 
        lock_kernel();
 
-       UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+       UFSD(("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment))
        if (fragment < 0)
                goto abort_negative;
        if (fragment >
index e9a42c711a9e386df42f329855e4683600eda25d..d4aacee593ffbb9a2daec491518ff9c4bf3dfec0 100644 (file)
@@ -221,7 +221,7 @@ void ufs_error (struct super_block * sb, const char * function,
        va_list args;
 
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
@@ -253,7 +253,7 @@ void ufs_panic (struct super_block * sb, const char * function,
        va_list args;
        
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
        
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_clean = UFS_FSBAD;
@@ -420,21 +420,18 @@ static int ufs_read_cylinder_structures (struct super_block *sb) {
                if (i + uspi->s_fpb > blks)
                        size = (blks - i) * uspi->s_fsize;
 
-               if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+               if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) 
                        ubh = ubh_bread(sb,
                                fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
-                       if (!ubh)
-                               goto failed;
-                       ubh_ubhcpymem (space, ubh, size);
-                       sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
-               }
-               else {
+               else 
                        ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-                       if (!ubh)
-                               goto failed;
-                       ubh_ubhcpymem(space, ubh, size);
-                       sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
-               }
+               
+               if (!ubh)
+                       goto failed;
+
+               ubh_ubhcpymem (space, ubh, size);
+               sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
+
                space += size;
                ubh_brelse (ubh);
                ubh = NULL;
@@ -539,6 +536,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *inode;
        unsigned block_size, super_block_size;
        unsigned flags;
+       unsigned super_block_offset;
 
        uspi = NULL;
        ubh = NULL;
@@ -586,10 +584,11 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
        if (!uspi)
                goto failed;
 
+       super_block_offset=UFS_SBLOCK;
+
        /* Keep 2Gig file limit. Some UFS variants need to override 
           this but as I don't know which I'll let those in the know loosen
           the rules */
-          
        switch (sbi->s_mount_opt & UFS_MOUNT_UFSTYPE) {
        case UFS_MOUNT_UFSTYPE_44BSD:
                UFSD(("ufstype=44bsd\n"))
@@ -601,7 +600,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
                flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
                break;
        case UFS_MOUNT_UFSTYPE_UFS2:
-               UFSD(("ufstype=ufs2\n"))
+               UFSD(("ufstype=ufs2\n"));
+               super_block_offset=SBLOCK_UFS2;
                uspi->s_fsize = block_size = 512;
                uspi->s_fmask = ~(512 - 1);
                uspi->s_fshift = 9;
@@ -725,19 +725,16 @@ again:
        /*
         * read ufs super block from device
         */
-       if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
-               ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size);
-       }
-       else {
-               ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
-       }
+
+       ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + super_block_offset/block_size, super_block_size);
+       
        if (!ubh) 
             goto failed;
 
        
-       usb1 = ubh_get_usb_first(USPI_UBH);
-       usb2 = ubh_get_usb_second(USPI_UBH);
-       usb3 = ubh_get_usb_third(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
+       usb2 = ubh_get_usb_second(uspi);
+       usb3 = ubh_get_usb_third(uspi);
        usb  = (struct ufs_super_block *)
                ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
@@ -1006,8 +1003,8 @@ static void ufs_write_super (struct super_block *sb) {
        UFSD(("ENTER\n"))
        flags = UFS_SB(sb)->s_flags;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(USPI_UBH);
-       usb3 = ubh_get_usb_third(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
+       usb3 = ubh_get_usb_third(uspi);
 
        if (!(sb->s_flags & MS_RDONLY)) {
                usb1->fs_time = cpu_to_fs32(sb, get_seconds());
@@ -1049,8 +1046,8 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)
        
        uspi = UFS_SB(sb)->s_uspi;
        flags = UFS_SB(sb)->s_flags;
-       usb1 = ubh_get_usb_first(USPI_UBH);
-       usb3 = ubh_get_usb_third(USPI_UBH);
+       usb1 = ubh_get_usb_first(uspi);
+       usb3 = ubh_get_usb_third(uspi);
        
        /*
         * Allow the "check" option to be passed as a remount option.
@@ -1124,7 +1121,7 @@ static int ufs_statfs (struct super_block *sb, struct kstatfs *buf)
        lock_kernel();
 
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first (USPI_UBH);
+       usb1 = ubh_get_usb_first (uspi);
        usb  = (struct ufs_super_block *)
                ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
        
index b2640076679a655769de7a8a3a8f3a255d61f9b3..48d6d9bcc15770ce05cd8a8c8bb08e3e5f88e26e 100644 (file)
@@ -249,18 +249,28 @@ extern void _ubh_memcpyubh_(struct ufs_sb_private_info *, struct ufs_buffer_head
 
 
 /*
- * macros to get important structures from ufs_buffer_head
+ * macros and inline function to get important structures from ufs_sb_private_info
  */
-#define ubh_get_usb_first(ubh) \
-       ((struct ufs_super_block_first *)((ubh)->bh[0]->b_data))
 
-#define ubh_get_usb_second(ubh) \
-       ((struct ufs_super_block_second *)(ubh)-> \
-       bh[UFS_SECTOR_SIZE >> uspi->s_fshift]->b_data + (UFS_SECTOR_SIZE & ~uspi->s_fmask))
+static inline void *get_usb_offset(struct ufs_sb_private_info *uspi,
+                                  unsigned int offset)
+{
+       unsigned int index;
+       
+       index = offset >> uspi->s_fshift;
+       offset &= ~uspi->s_fmask;
+       return uspi->s_ubh.bh[index]->b_data + offset;
+}
+
+#define ubh_get_usb_first(uspi) \
+       ((struct ufs_super_block_first *)get_usb_offset((uspi), 0))
+
+#define ubh_get_usb_second(uspi) \
+       ((struct ufs_super_block_second *)get_usb_offset((uspi), UFS_SECTOR_SIZE))
+
+#define ubh_get_usb_third(uspi)        \
+       ((struct ufs_super_block_third *)get_usb_offset((uspi), 2*UFS_SECTOR_SIZE))
 
-#define ubh_get_usb_third(ubh) \
-       ((struct ufs_super_block_third *)((ubh)-> \
-       bh[UFS_SECTOR_SIZE*2 >> uspi->s_fshift]->b_data + (UFS_SECTOR_SIZE*2 & ~uspi->s_fmask)))
 
 #define ubh_get_ucg(ubh) \
        ((struct ufs_cylinder_group *)((ubh)->bh[0]->b_data))
index 8cf70ff160afb42b0d0a9e4415bb4d7d386d2238..2b57f91b4ebd891e540effb05cc258a1b1418668 100644 (file)
@@ -26,6 +26,8 @@
  * fc000000    da000000        16M             PCI CFG0
  * fd000000    d8000000        16M             PCI I/O
  * fe[0-7]00000                        8M              per-platform mappings
+ * fe900000    80000000        1M              SRAM #0 (first MB)
+ * fea00000    cb400000        1M              SCRATCH ring get/put
  * feb00000    c8000000        1M              MSF
  * fec00000    df000000        1M              PCI CSRs
  * fed00000    de000000        1M              PCI CREG
 #define IXP2000_MSF_VIRT_BASE          0xfeb00000
 #define IXP2000_MSF_SIZE               0x00100000
 
+#define IXP2000_SCRATCH_RING_PHYS_BASE 0xcb400000
+#define IXP2000_SCRATCH_RING_VIRT_BASE 0xfea00000
+#define IXP2000_SCRATCH_RING_SIZE      0x00100000
+
+#define IXP2000_SRAM0_PHYS_BASE                0x80000000
+#define IXP2000_SRAM0_VIRT_BASE                0xfe900000
+#define IXP2000_SRAM0_SIZE             0x00100000
+
 #define IXP2000_PCI_IO_PHYS_BASE       0xd8000000
 #define        IXP2000_PCI_IO_VIRT_BASE        0xfd000000
 #define IXP2000_PCI_IO_SIZE            0x01000000
index 58f0d71759f6606f342652b8f61702cf7e3a2168..feff771c0a0a950630cbef18d231da9c5d665d47 100644 (file)
@@ -8,6 +8,7 @@
  * warranty of any kind, whether express or implied.
  */
 #include <asm/hardware.h>
+#include <asm/hardware/vic.h>
 
                .macro  disable_fiq
                .endm
index cbdd9fb963320166473a3f2da845410d57cc6c56..72ef874567d57b2cb6ad0919e457af6830c4fef9 100644 (file)
  *     VERSATILE_SYS_IC 
  * 
  */
-#define VIC_IRQ_STATUS                  0
-#define VIC_FIQ_STATUS                  0x04
-#define VIC_IRQ_RAW_STATUS              0x08
-#define VIC_INT_SELECT                  0x0C   /* 1 = FIQ, 0 = IRQ */
-#define VIC_IRQ_ENABLE                  0x10   /* 1 = enable, 0 = disable */
-#define VIC_IRQ_ENABLE_CLEAR            0x14
-#define VIC_IRQ_SOFT                    0x18
-#define VIC_IRQ_SOFT_CLEAR              0x1C
-#define VIC_PROTECT                     0x20
-#define VIC_VECT_ADDR                   0x30
-#define VIC_DEF_VECT_ADDR               0x34
-#define VIC_VECT_ADDR0                  0x100  /* 0 to 15 */
-#define VIC_VECT_CNTL0                  0x200  /* 0 to 15 */
-#define VIC_ITCR                        0x300   /* VIC test control register */
-
-#define VIC_FIQ_RAW_STATUS              0x08
-#define VIC_FIQ_ENABLE                  0x10   /* 1 = enable, 0 = disable */
-#define VIC_FIQ_ENABLE_CLEAR            0x14
-#define VIC_FIQ_SOFT                    0x18
-#define VIC_FIQ_SOFT_CLEAR              0x1C
+/* VIC definitions in include/asm-arm/hardware/vic.h */
 
 #define SIC_IRQ_STATUS                  0
 #define SIC_IRQ_RAW_STATUS              0x04
 #define SIC_INT_PIC_ENABLES             0x20   /* set interrupt pass through bits */
 #define SIC_INT_PIC_ENABLEC             0x24   /* Clear interrupt pass through bits */
 
-#define VICVectCntl_Enable             (1 << 5)
-
 /* ------------------------------------------------------------------------
  *  Interrupts - bit assignment (primary)
  * ------------------------------------------------------------------------
diff --git a/include/asm-arm/hardware/vic.h b/include/asm-arm/hardware/vic.h
new file mode 100644 (file)
index 0000000..81825eb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  linux/include/asm-arm/hardware/vic.h
+ *
+ *  Copyright (c) ARM Limited 2003.  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
+ */
+#ifndef __ASM_ARM_HARDWARE_VIC_H
+#define __ASM_ARM_HARDWARE_VIC_H
+
+#define VIC_IRQ_STATUS                 0x00
+#define VIC_FIQ_STATUS                 0x04
+#define VIC_RAW_STATUS                 0x08
+#define VIC_INT_SELECT                 0x0c    /* 1 = FIQ, 0 = IRQ */
+#define VIC_INT_ENABLE                 0x10    /* 1 = enable, 0 = disable */
+#define VIC_INT_ENABLE_CLEAR           0x14
+#define VIC_INT_SOFT                   0x18
+#define VIC_INT_SOFT_CLEAR             0x1c
+#define VIC_PROTECT                    0x20
+#define VIC_VECT_ADDR                  0x30
+#define VIC_DEF_VECT_ADDR              0x34
+
+#define VIC_VECT_ADDR0                 0x100   /* 0 to 15 */
+#define VIC_VECT_CNTL0                 0x200   /* 0 to 15 */
+#define VIC_ITCR                       0x300   /* VIC test control register */
+
+#define VIC_VECT_CNTL_ENABLE           (1 << 5)
+
+#ifndef __ASSEMBLY__
+void vic_init(void __iomem *base, u32 vic_sources);
+#endif
+
+#endif
index eb262e078c46edf4c126e635e4279bb73437630d..2cd57b4d64d9f4d0a70f340d1110bc03439a6426 100644 (file)
@@ -10,6 +10,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/compiler.h>
+
 struct tag;
 struct meminfo;
 struct sys_timer;
@@ -20,7 +22,7 @@ struct machine_desc {
         * by assembler code in head-armv.S
         */
        unsigned int            nr;             /* architecture number  */
-       unsigned int            phys_ram;       /* start of physical ram */
+       unsigned int __deprecated phys_ram;     /* start of physical ram */
        unsigned int            phys_io;        /* start of physical io */
        unsigned int            io_pg_offst;    /* byte offset for io 
                                                 * page tabe entry      */
index 4da1d532cbebd751ecba5ead32ba866ca8f9f7db..416320d95419579178b82ea6aba75a381be7e706 100644 (file)
@@ -170,6 +170,13 @@ extern pmd_t *top_pmd;
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+/*
+ * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
+ */
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define ARCH_SLAB_MINALIGN 8
+#endif
+
 #endif /* __KERNEL__ */
 
 #include <asm-generic/page.h>
index 31290694648b095d2a4595c91a9b2825bb72bf6b..04f4d34c63170736e9f6301f63a3b666c06f6303 100644 (file)
@@ -49,6 +49,12 @@ struct thread_struct {
 
 #define INIT_THREAD  { }
 
+#ifdef CONFIG_MMU
+#define nommu_start_thread(regs) do { } while (0)
+#else
+#define nommu_start_thread(regs) regs->ARM_r10 = current->mm->start_data
+#endif
+
 #define start_thread(regs,pc,sp)                                       \
 ({                                                                     \
        unsigned long *stack = (unsigned long *)sp;                     \
@@ -65,6 +71,7 @@ struct thread_struct {
        regs->ARM_r2 = stack[2];        /* r2 (envp) */                 \
        regs->ARM_r1 = stack[1];        /* r1 (argv) */                 \
        regs->ARM_r0 = stack[0];        /* r0 (argc) */                 \
+       nommu_start_thread(regs);                                       \
 })
 
 /* Forward declaration, a strange C thing */
index 4377e22b7e1a9a7359d1e6255e4098b1227e7aa2..77adb7fa169bb291368589f4fc206821f2988707 100644 (file)
@@ -23,6 +23,9 @@
 #define PTRACE_OLDSETOPTIONS   21
 
 #define PTRACE_GET_THREAD_AREA 22
+
+#define PTRACE_SET_SYSCALL     23
+
 /*
  * PSR bits
  */
 
 #ifndef __ASSEMBLY__
 
-/* this struct defines the way the registers are stored on the
-   stack during a system call. */
-
+/*
+ * This struct defines the way the registers are stored on the
+ * stack during a system call.  Note that sizeof(struct pt_regs)
+ * has to be a multiple of 8.
+ */
 struct pt_regs {
        long uregs[18];
 };
index ec4e2c2e3b4754503566b706b2a83e7bf7b5fe00..42c0c13999d5ffa4f8458d2825cd121a41dd8595 100644 (file)
@@ -70,14 +70,7 @@ struct stat64 {
 
        long long       st_size;
        unsigned long   st_blksize;
-
-#if defined(__ARMEB__)
-       unsigned long   __pad4;         /* Future possible st_blocks hi bits */
-       unsigned long   st_blocks;      /* Number 512-byte blocks allocated. */
-#else /* Must be little */
-       unsigned long   st_blocks;      /* Number 512-byte blocks allocated. */
-       unsigned long   __pad4;         /* Future possible st_blocks hi bits */
-#endif
+       unsigned long long st_blocks;   /* Number 512-byte blocks allocated. */
 
        unsigned long   st_atime;
        unsigned long   st_atime_nsec;
@@ -89,6 +82,6 @@ struct stat64 {
        unsigned long   st_ctime_nsec;
 
        unsigned long long      st_ino;
-} __attribute__((packed));
+};
 
 #endif
index e81f82783b878d64717af7885a1842e56c1b4929..a02e6a8c3d70ac2d681ef9dd35a426426f1b0ae4 100644 (file)
@@ -1,6 +1,42 @@
 #ifndef _ASMARM_STATFS_H
 #define _ASMARM_STATFS_H
 
-#include <asm-generic/statfs.h>
+#ifndef __KERNEL_STRICT_NAMES
+# include <linux/types.h>
+typedef __kernel_fsid_t        fsid_t;
+#endif
+
+struct statfs {
+       __u32 f_type;
+       __u32 f_bsize;
+       __u32 f_blocks;
+       __u32 f_bfree;
+       __u32 f_bavail;
+       __u32 f_files;
+       __u32 f_ffree;
+       __kernel_fsid_t f_fsid;
+       __u32 f_namelen;
+       __u32 f_frsize;
+       __u32 f_spare[5];
+};
+
+/*
+ * With EABI there is 4 bytes of padding added to this structure.
+ * Let's pack it so the padding goes away to simplify dual ABI support.
+ * Note that user space does NOT have to pack this structure.
+ */
+struct statfs64 {
+       __u32 f_type;
+       __u32 f_bsize;
+       __u64 f_blocks;
+       __u64 f_bfree;
+       __u64 f_bavail;
+       __u64 f_files;
+       __u64 f_ffree;
+       __kernel_fsid_t f_fsid;
+       __u32 f_namelen;
+       __u32 f_frsize;
+       __u32 f_spare[5];
+} __attribute__ ((packed,aligned(4)));
 
 #endif
index d626e70fadedd520fd342fa49f51cc39b2118014..77430d6178aee6d47ca145de21b6422057542b3b 100644 (file)
 
 #include <linux/linkage.h>
 
-#if defined(__thumb__)
+#define __NR_OABI_SYSCALL_BASE 0x900000
+
+#if defined(__thumb__) || defined(__ARM_EABI__)
 #define __NR_SYSCALL_BASE      0
 #else
-#define __NR_SYSCALL_BASE      0x900000
+#define __NR_SYSCALL_BASE      __NR_OABI_SYSCALL_BASE
 #endif
 
 /*
 #define __sys1(x) __sys2(x)
 
 #ifndef __syscall
-#if defined(__thumb__)
-#define __syscall(name)                                        \
-       "push   {r7}\n\t"                               \
-       "mov    r7, #" __sys1(__NR_##name) "\n\t"       \
-       "swi    0\n\t"                                  \
-       "pop    {r7}"
+#if defined(__thumb__) || defined(__ARM_EABI__)
+#define __SYS_REG(name) register long __sysreg __asm__("r7") = __NR_##name;
+#define __SYS_REG_LIST(regs...) "r" (__sysreg) , ##regs
+#define __syscall(name) "swi\t0"
 #else
+#define __SYS_REG(name)
+#define __SYS_REG_LIST(regs...) regs
 #define __syscall(name) "swi\t" __sys1(__NR_##name) ""
 #endif
 #endif
@@ -395,33 +397,34 @@ do {                                                                      \
 
 #define _syscall0(type,name)                                           \
 type name(void) {                                                      \
+  __SYS_REG(name)                                                      \
   register long __res_r0 __asm__("r0");                                        \
   long __res;                                                          \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       :                                                               \
-       : "lr");                                                        \
+       : __SYS_REG_LIST() );                                           \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #define _syscall1(type,name,type1,arg1)                                \
 type name(type1 arg1) {                                                \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __res_r0 __asm__("r0");                                        \
   long __res;                                                          \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0)                                                    \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0) ) );                               \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2)                     \
 type name(type1 arg1,type2 arg2) {                                     \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __res_r0 __asm__("r0");                                        \
@@ -429,8 +432,7 @@ type name(type1 arg1,type2 arg2) {                                  \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1)                                         \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1) ) );                   \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
@@ -438,6 +440,7 @@ type name(type1 arg1,type2 arg2) {                                  \
 
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)          \
 type name(type1 arg1,type2 arg2,type3 arg3) {                          \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -446,8 +449,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) {                               \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2)                              \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2) ) );       \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
@@ -455,6 +457,7 @@ type name(type1 arg1,type2 arg2,type3 arg3) {                               \
 
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {            \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -464,8 +467,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {         \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3)                   \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) ) ); \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
@@ -473,6 +475,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {         \
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)    \
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {        \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -483,14 +486,15 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {   \
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4)        \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2),           \
+                         "r" (__r3), "r" (__r4) ) );                   \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) {    \
+  __SYS_REG(name)                                                      \
   register long __r0 __asm__("r0") = (long)arg1;                       \
   register long __r1 __asm__("r1") = (long)arg2;                       \
   register long __r2 __asm__("r2") = (long)arg3;                       \
@@ -502,30 +506,33 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
   __asm__ __volatile__ (                                               \
   __syscall(name)                                                      \
        : "=r" (__res_r0)                                               \
-       : "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5)            \
-       : "lr");                                                        \
+       : __SYS_REG_LIST( "0" (__r0), "r" (__r1), "r" (__r2),           \
+                         "r" (__r3), "r" (__r4), "r" (__r5) ) );       \
   __res = __res_r0;                                                    \
   __syscall_return(type,__res);                                                \
 }
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
 #define __ARCH_WANT_SYS_GETHOSTNAME
 #define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_SOCKETCALL
 #define __ARCH_WANT_SYS_GETPGRP
 #define __ARCH_WANT_SYS_LLSEEK
 #define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLD_GETRLIMIT
-#define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+
+#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_OLD_GETRLIMIT
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_SYS_SOCKETCALL
+#endif
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
index 0fada8f16dc6d8f6ca0a1f2907684edefdcf76c6..42a95d9a0641b4059a96b464d7d0a0e38cbd1b33 100644 (file)
@@ -35,7 +35,7 @@ static inline void atomic_long_set(atomic_long_t *l, long i)
 {
        atomic64_t *v = (atomic64_t *)l;
 
-       atomic_set(v, i);
+       atomic64_set(v, i);
 }
 
 static inline void atomic_long_inc(atomic_long_t *l)
index fe0819fe9c6496584ff958393c2f6a5381bd9b47..88e6ca248cd74f0a2a17f033a34c98d80df5e0f6 100644 (file)
@@ -247,7 +247,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long* addr)
 static int test_bit(int nr, const volatile void * addr);
 #endif
 
-static inline int constant_test_bit(int nr, const volatile unsigned long *addr)
+static __always_inline int constant_test_bit(int nr, const volatile unsigned long *addr)
 {
        return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
 }
index d97328951f5f027b767c28cf44b44f1abfd52aff..3cbbecd790161babf7fa1df4a7c549d4c2107276 100644 (file)
@@ -5,7 +5,7 @@
 
 struct task_struct;
 
-static inline struct task_struct * get_current(void)
+static __always_inline struct task_struct * get_current(void)
 {
        return current_thread_info()->task;
 }
index 02c8f5d22065df19ec9adab857aabcd8a5627364..bb5f88a27f7a8e23711afa0aa8ca5f30d1ed95c7 100644 (file)
@@ -201,7 +201,7 @@ __asm__ __volatile__(
 return __res;
 }
 
-static inline void * __memcpy(void * to, const void * from, size_t n)
+static __always_inline void * __memcpy(void * to, const void * from, size_t n)
 {
 int d0, d1, d2;
 __asm__ __volatile__(
@@ -223,7 +223,7 @@ return (to);
  * This looks ugly, but the compiler can optimize it totally,
  * as the count is constant.
  */
-static inline void * __constant_memcpy(void * to, const void * from, size_t n)
+static __always_inline void * __constant_memcpy(void * to, const void * from, size_t n)
 {
        long esi, edi;
        if (!n) return to;
@@ -367,7 +367,7 @@ return s;
  * things 32 bits at a time even when we don't know the size of the
  * area at compile-time..
  */
-static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
+static __always_inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
 {
 int d0, d1;
 __asm__ __volatile__(
@@ -416,7 +416,7 @@ extern char *strstr(const char *cs, const char *ct);
  * This looks horribly ugly, but the compiler can optimize it totally,
  * as we by now know that both pattern and count is constant..
  */
-static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
+static __always_inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
 {
        switch (count) {
                case 0:
index 89ab7e2bc5aaac8a1e230fbd7772ff5340e7b3a1..3f1337c342087561483c5d604396a227ce4664ce 100644 (file)
@@ -411,7 +411,7 @@ unsigned long __must_check __copy_from_user_ll(void *to,
  * Returns number of bytes that could not be copied.
  * On success, this will be zero.
  */
-static inline unsigned long __must_check
+static __always_inline unsigned long __must_check
 __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
 {
        if (__builtin_constant_p(n)) {
@@ -432,7 +432,7 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
        return __copy_to_user_ll(to, from, n);
 }
 
-static inline unsigned long __must_check
+static __always_inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
        might_sleep();
@@ -456,7 +456,7 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
  * If some data could not be copied, this function will pad the copied
  * data to the requested size using zero bytes.
  */
-static inline unsigned long
+static __always_inline unsigned long
 __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
 {
        if (__builtin_constant_p(n)) {
@@ -477,7 +477,7 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
        return __copy_from_user_ll(to, from, n);
 }
 
-static inline unsigned long
+static __always_inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
        might_sleep();
index a74b68104559a556e335e80b7262c46594086a89..8c0fc227f0fb6934c4f3f7573456d5d21150c6e0 100644 (file)
@@ -68,10 +68,14 @@ struct prev_kprobe {
        unsigned long status;
 };
 
+#define        MAX_PARAM_RSE_SIZE      (0x60+0x60/0x3f)
 /* per-cpu kprobe control block */
 struct kprobe_ctlblk {
        unsigned long kprobe_status;
        struct pt_regs jprobe_saved_regs;
+       unsigned long jprobes_saved_stacked_regs[MAX_PARAM_RSE_SIZE];
+       unsigned long *bsp;
+       unsigned long cfm;
        struct prev_kprobe prev_kprobe;
 };
 
@@ -118,5 +122,7 @@ extern int kprobe_exceptions_notify(struct notifier_block *self,
 static inline void jprobe_return(void)
 {
 }
+extern void invalidate_stacked_regs(void);
+extern void flush_register_stack(void);
 
 #endif                         /* _ASM_KPROBES_H */
diff --git a/include/asm-ia64/sn/ioc3.h b/include/asm-ia64/sn/ioc3.h
new file mode 100644 (file)
index 0000000..95ed6cc
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2005 Silicon Graphics, Inc.
+ */
+#ifndef IA64_SN_IOC3_H
+#define IA64_SN_IOC3_H
+
+/* serial port register map */
+struct ioc3_serialregs {
+       uint32_t sscr;
+       uint32_t stpir;
+       uint32_t stcir;
+       uint32_t srpir;
+       uint32_t srcir;
+       uint32_t srtr;
+       uint32_t shadow;
+};
+
+/* SUPERIO uart register map */
+struct ioc3_uartregs {
+       char iu_lcr;
+       union {
+               char iir;       /* read only */
+               char fcr;       /* write only */
+       } u3;
+       union {
+               char ier;       /* DLAB == 0 */
+               char dlm;       /* DLAB == 1 */
+       } u2;
+       union {
+               char rbr;       /* read only, DLAB == 0 */
+               char thr;       /* write only, DLAB == 0 */
+               char dll;       /* DLAB == 1 */
+       } u1;
+       char iu_scr;
+       char iu_msr;
+       char iu_lsr;
+       char iu_mcr;
+};
+
+#define iu_rbr u1.rbr
+#define iu_thr u1.thr
+#define iu_dll u1.dll
+#define iu_ier u2.ier
+#define iu_dlm u2.dlm
+#define iu_iir u3.iir
+#define iu_fcr u3.fcr
+
+struct ioc3_sioregs {
+       char fill[0x170];
+       struct ioc3_uartregs uartb;
+       struct ioc3_uartregs uarta;
+};
+
+/* PCI IO/mem space register map */
+struct ioc3 {
+       uint32_t pci_id;
+       uint32_t pci_scr;
+       uint32_t pci_rev;
+       uint32_t pci_lat;
+       uint32_t pci_addr;
+       uint32_t pci_err_addr_l;
+       uint32_t pci_err_addr_h;
+
+       uint32_t sio_ir;
+       /* these registers are read-only for general kernel code. To
+        * modify them use the functions in ioc3.c
+        */
+       uint32_t sio_ies;
+       uint32_t sio_iec;
+       uint32_t sio_cr;
+       uint32_t int_out;
+       uint32_t mcr;
+       uint32_t gpcr_s;
+       uint32_t gpcr_c;
+       uint32_t gpdr;
+       uint32_t gppr[9];
+       char fill[0x4c];
+
+       /* serial port registers */
+       uint32_t sbbr_h;
+       uint32_t sbbr_l;
+
+       struct ioc3_serialregs port_a;
+       struct ioc3_serialregs port_b;
+       char fill1[0x1ff10];
+       /* superio registers */
+       struct ioc3_sioregs sregs;
+};
+
+/* These don't exist on the ioc3 serial card... */
+#define eier   fill1[8]
+#define eisr   fill1[4]
+
+#define PCI_LAT                        0xc     /* Latency Timer */
+#define PCI_SCR_DROP_MODE_EN   0x00008000 /* drop pios on parity err */
+#define UARTA_BASE             0x178
+#define UARTB_BASE             0x170
+
+
+/* bitmasks for serial RX status byte */
+#define RXSB_OVERRUN           0x01    /* char(s) lost */
+#define RXSB_PAR_ERR           0x02    /* parity error */
+#define RXSB_FRAME_ERR         0x04    /* framing error */
+#define RXSB_BREAK             0x08    /* break character */
+#define RXSB_CTS               0x10    /* state of CTS */
+#define RXSB_DCD               0x20    /* state of DCD */
+#define RXSB_MODEM_VALID       0x40    /* DCD, CTS and OVERRUN are valid */
+#define RXSB_DATA_VALID                0x80    /* FRAME_ERR PAR_ERR & BREAK valid */
+
+/* bitmasks for serial TX control byte */
+#define TXCB_INT_WHEN_DONE     0x20    /* interrupt after this byte is sent */
+#define TXCB_INVALID           0x00    /* byte is invalid */
+#define TXCB_VALID             0x40    /* byte is valid */
+#define TXCB_MCR               0x80    /* data<7:0> to modem cntrl register */
+#define TXCB_DELAY             0xc0    /* delay data<7:0> mSec */
+
+/* bitmasks for SBBR_L */
+#define SBBR_L_SIZE            0x00000001      /* 0 1KB rings, 1 4KB rings */
+
+/* bitmasks for SSCR_<A:B> */
+#define SSCR_RX_THRESHOLD      0x000001ff      /* hiwater mark */
+#define SSCR_TX_TIMER_BUSY     0x00010000      /* TX timer in progress */
+#define SSCR_HFC_EN            0x00020000      /* h/w flow cntrl enabled */
+#define SSCR_RX_RING_DCD       0x00040000      /* postRX record on delta-DCD */
+#define SSCR_RX_RING_CTS       0x00080000      /* postRX record on delta-CTS */
+#define SSCR_HIGH_SPD          0x00100000      /* 4X speed */
+#define SSCR_DIAG              0x00200000      /* bypass clock divider */
+#define SSCR_RX_DRAIN          0x08000000      /* drain RX buffer to memory */
+#define SSCR_DMA_EN            0x10000000      /* enable ring buffer DMA */
+#define SSCR_DMA_PAUSE         0x20000000      /* pause DMA */
+#define SSCR_PAUSE_STATE       0x40000000      /* set when PAUSE takes effect*/
+#define SSCR_RESET             0x80000000      /* reset DMA channels */
+
+/* all producer/comsumer pointers are the same bitfield */
+#define PROD_CONS_PTR_4K       0x00000ff8      /* for 4K buffers */
+#define PROD_CONS_PTR_1K       0x000003f8      /* for 1K buffers */
+#define PROD_CONS_PTR_OFF      3
+
+/* bitmasks for SRCIR_<A:B> */
+#define SRCIR_ARM              0x80000000      /* arm RX timer */
+
+/* bitmasks for SHADOW_<A:B> */
+#define SHADOW_DR              0x00000001      /* data ready */
+#define SHADOW_OE              0x00000002      /* overrun error */
+#define SHADOW_PE              0x00000004      /* parity error */
+#define SHADOW_FE              0x00000008      /* framing error */
+#define SHADOW_BI              0x00000010      /* break interrupt */
+#define SHADOW_THRE            0x00000020      /* transmit holding reg empty */
+#define SHADOW_TEMT            0x00000040      /* transmit shift reg empty */
+#define SHADOW_RFCE            0x00000080      /* char in RX fifo has error */
+#define SHADOW_DCTS            0x00010000      /* delta clear to send */
+#define SHADOW_DDCD            0x00080000      /* delta data carrier detect */
+#define SHADOW_CTS             0x00100000      /* clear to send */
+#define SHADOW_DCD             0x00800000      /* data carrier detect */
+#define SHADOW_DTR             0x01000000      /* data terminal ready */
+#define SHADOW_RTS             0x02000000      /* request to send */
+#define SHADOW_OUT1            0x04000000      /* 16550 OUT1 bit */
+#define SHADOW_OUT2            0x08000000      /* 16550 OUT2 bit */
+#define SHADOW_LOOP            0x10000000      /* loopback enabled */
+
+/* bitmasks for SRTR_<A:B> */
+#define SRTR_CNT               0x00000fff      /* reload value for RX timer */
+#define SRTR_CNT_VAL           0x0fff0000      /* current value of RX timer */
+#define SRTR_CNT_VAL_SHIFT     16
+#define SRTR_HZ                        16000           /* SRTR clock frequency */
+
+/* bitmasks for SIO_IR, SIO_IEC and SIO_IES  */
+#define SIO_IR_SA_TX_MT                0x00000001      /* Serial port A TX empty */
+#define SIO_IR_SA_RX_FULL      0x00000002      /* port A RX buf full */
+#define SIO_IR_SA_RX_HIGH      0x00000004      /* port A RX hiwat */
+#define SIO_IR_SA_RX_TIMER     0x00000008      /* port A RX timeout */
+#define SIO_IR_SA_DELTA_DCD    0x00000010      /* port A delta DCD */
+#define SIO_IR_SA_DELTA_CTS    0x00000020      /* port A delta CTS */
+#define SIO_IR_SA_INT          0x00000040      /* port A pass-thru intr */
+#define SIO_IR_SA_TX_EXPLICIT  0x00000080      /* port A explicit TX thru */
+#define SIO_IR_SA_MEMERR       0x00000100      /* port A PCI error */
+#define SIO_IR_SB_TX_MT                0x00000200
+#define SIO_IR_SB_RX_FULL      0x00000400
+#define SIO_IR_SB_RX_HIGH      0x00000800
+#define SIO_IR_SB_RX_TIMER     0x00001000
+#define SIO_IR_SB_DELTA_DCD    0x00002000
+#define SIO_IR_SB_DELTA_CTS    0x00004000
+#define SIO_IR_SB_INT          0x00008000
+#define SIO_IR_SB_TX_EXPLICIT  0x00010000
+#define SIO_IR_SB_MEMERR       0x00020000
+#define SIO_IR_PP_INT          0x00040000      /* P port pass-thru intr */
+#define SIO_IR_PP_INTA         0x00080000      /* PP context A thru */
+#define SIO_IR_PP_INTB         0x00100000      /* PP context B thru */
+#define SIO_IR_PP_MEMERR       0x00200000      /* PP PCI error */
+#define SIO_IR_KBD_INT         0x00400000      /* kbd/mouse intr */
+#define SIO_IR_RT_INT          0x08000000      /* RT output pulse */
+#define SIO_IR_GEN_INT1                0x10000000      /* RT input pulse */
+#define SIO_IR_GEN_INT_SHIFT   28
+
+/* per device interrupt masks */
+#define SIO_IR_SA              (SIO_IR_SA_TX_MT | \
+                                SIO_IR_SA_RX_FULL | \
+                                SIO_IR_SA_RX_HIGH | \
+                                SIO_IR_SA_RX_TIMER | \
+                                SIO_IR_SA_DELTA_DCD | \
+                                SIO_IR_SA_DELTA_CTS | \
+                                SIO_IR_SA_INT | \
+                                SIO_IR_SA_TX_EXPLICIT | \
+                                SIO_IR_SA_MEMERR)
+
+#define SIO_IR_SB              (SIO_IR_SB_TX_MT | \
+                                SIO_IR_SB_RX_FULL | \
+                                SIO_IR_SB_RX_HIGH | \
+                                SIO_IR_SB_RX_TIMER | \
+                                SIO_IR_SB_DELTA_DCD | \
+                                SIO_IR_SB_DELTA_CTS | \
+                                SIO_IR_SB_INT | \
+                                SIO_IR_SB_TX_EXPLICIT | \
+                                SIO_IR_SB_MEMERR)
+
+#define SIO_IR_PP              (SIO_IR_PP_INT | SIO_IR_PP_INTA | \
+                                SIO_IR_PP_INTB | SIO_IR_PP_MEMERR)
+#define SIO_IR_RT              (SIO_IR_RT_INT | SIO_IR_GEN_INT1)
+
+/* bitmasks for SIO_CR */
+#define SIO_CR_CMD_PULSE_SHIFT 15
+#define SIO_CR_SER_A_BASE_SHIFT 1
+#define SIO_CR_SER_B_BASE_SHIFT 8
+#define SIO_CR_ARB_DIAG                0x00380000      /* cur !enet PCI requet (ro) */
+#define SIO_CR_ARB_DIAG_TXA    0x00000000
+#define SIO_CR_ARB_DIAG_RXA    0x00080000
+#define SIO_CR_ARB_DIAG_TXB    0x00100000
+#define SIO_CR_ARB_DIAG_RXB    0x00180000
+#define SIO_CR_ARB_DIAG_PP     0x00200000
+#define SIO_CR_ARB_DIAG_IDLE   0x00400000      /* 0 -> active request (ro) */
+
+/* defs for some of the generic I/O pins */
+#define GPCR_PHY_RESET         0x20    /* pin is output to PHY reset */
+#define GPCR_UARTB_MODESEL     0x40    /* pin is output to port B mode sel */
+#define GPCR_UARTA_MODESEL     0x80    /* pin is output to port A mode sel */
+
+#define GPPR_PHY_RESET_PIN     5       /* GIO pin controlling phy reset */
+#define GPPR_UARTB_MODESEL_PIN 6       /* GIO pin cntrling uartb modeselect */
+#define GPPR_UARTA_MODESEL_PIN 7       /* GIO pin cntrling uarta modeselect */
+
+#endif /* IA64_SN_IOC3_H */
index 2a8b0d92a5d62f139ec98cb0e125883c7e39e122..8b9e10e7cdba89bc9546ab1c6d06a41a35475487 100644 (file)
@@ -75,7 +75,8 @@
 #define  SN_SAL_IOIF_GET_HUBDEV_INFO              0x02000055
 #define  SN_SAL_IOIF_GET_PCIBUS_INFO              0x02000056
 #define  SN_SAL_IOIF_GET_PCIDEV_INFO              0x02000057
-#define  SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST     0x02000058
+#define  SN_SAL_IOIF_GET_WIDGET_DMAFLUSH_LIST     0x02000058   // deprecated
+#define  SN_SAL_IOIF_GET_DEVICE_DMAFLUSH_LIST     0x0200005a
 
 #define SN_SAL_HUB_ERROR_INTERRUPT                0x02000060
 #define SN_SAL_BTE_RECOVER                        0x02000061
@@ -1100,7 +1101,7 @@ ia64_sn_bte_recovery(nasid_t nasid)
        struct ia64_sal_retval rv;
 
        rv.status = 0;
-       SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, 0, 0, 0, 0, 0, 0, 0);
+       SAL_CALL_NOLOCK(rv, SN_SAL_BTE_RECOVER, (u64)nasid, 0, 0, 0, 0, 0, 0);
        if (rv.status == SALRET_NOT_IMPLEMENTED)
                return 0;
        return (int) rv.status;
index 49faf8f26430806f6fa19fc39a6d8b65f914fe04..203945ae034e1c70e5a8aee672a6b40e22bbfdc1 100644 (file)
@@ -227,7 +227,9 @@ enum xpc_retval {
 
        xpcOpenCloseError,      /* 50: channel open/close protocol error */
 
-       xpcUnknownReason        /* 51: unknown reason -- must be last in list */
+       xpcDisconnected,        /* 51: channel disconnected (closed) */
+
+       xpcUnknownReason        /* 52: unknown reason -- must be last in list */
 };
 
 
diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h
new file mode 100644 (file)
index 0000000..87e9cd5
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * 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) 2004-2006 Silicon Graphics, Inc.  All Rights Reserved.
+ */
+
+
+/*
+ * Cross Partition Communication (XPC) structures and macros.
+ */
+
+#ifndef _ASM_IA64_SN_XPC_H
+#define _ASM_IA64_SN_XPC_H
+
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/device.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/clksupport.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/mspec.h>
+#include <asm/sn/shub_mmr.h>
+#include <asm/sn/xp.h>
+
+
+/*
+ * XPC Version numbers consist of a major and minor number. XPC can always
+ * talk to versions with same major #, and never talk to versions with a
+ * different major #.
+ */
+#define _XPC_VERSION(_maj, _min)       (((_maj) << 4) | ((_min) & 0xf))
+#define XPC_VERSION_MAJOR(_v)          ((_v) >> 4)
+#define XPC_VERSION_MINOR(_v)          ((_v) & 0xf)
+
+
+/*
+ * The next macros define word or bit representations for given
+ * C-brick nasid in either the SAL provided bit array representing
+ * nasids in the partition/machine or the AMO_t array used for
+ * inter-partition initiation communications.
+ *
+ * For SN2 machines, C-Bricks are alway even numbered NASIDs.  As
+ * such, some space will be saved by insisting that nasid information
+ * passed from SAL always be packed for C-Bricks and the
+ * cross-partition interrupts use the same packing scheme.
+ */
+#define XPC_NASID_W_INDEX(_n)  (((_n) / 64) / 2)
+#define XPC_NASID_B_INDEX(_n)  (((_n) / 2) & (64 - 1))
+#define XPC_NASID_IN_ARRAY(_n, _p) ((_p)[XPC_NASID_W_INDEX(_n)] & \
+                                   (1UL << XPC_NASID_B_INDEX(_n)))
+#define XPC_NASID_FROM_W_B(_w, _b) (((_w) * 64 + (_b)) * 2)
+
+#define XPC_HB_DEFAULT_INTERVAL                5       /* incr HB every x secs */
+#define XPC_HB_CHECK_DEFAULT_INTERVAL  20      /* check HB every x secs */
+
+/* define the process name of HB checker and the CPU it is pinned to */
+#define XPC_HB_CHECK_THREAD_NAME       "xpc_hb"
+#define XPC_HB_CHECK_CPU               0
+
+/* define the process name of the discovery thread */
+#define XPC_DISCOVERY_THREAD_NAME      "xpc_discovery"
+
+
+/*
+ * the reserved page
+ *
+ *   SAL reserves one page of memory per partition for XPC. Though a full page
+ *   in length (16384 bytes), its starting address is not page aligned, but it
+ *   is cacheline aligned. The reserved page consists of the following:
+ *
+ *   reserved page header
+ *
+ *     The first cacheline of the reserved page contains the header
+ *     (struct xpc_rsvd_page). Before SAL initialization has completed,
+ *     SAL has set up the following fields of the reserved page header:
+ *     SAL_signature, SAL_version, partid, and nasids_size. The other
+ *     fields are set up by XPC. (xpc_rsvd_page points to the local
+ *     partition's reserved page.)
+ *
+ *   part_nasids mask
+ *   mach_nasids mask
+ *
+ *     SAL also sets up two bitmaps (or masks), one that reflects the actual
+ *     nasids in this partition (part_nasids), and the other that reflects
+ *     the actual nasids in the entire machine (mach_nasids). We're only
+ *     interested in the even numbered nasids (which contain the processors
+ *     and/or memory), so we only need half as many bits to represent the
+ *     nasids. The part_nasids mask is located starting at the first cacheline
+ *     following the reserved page header. The mach_nasids mask follows right
+ *     after the part_nasids mask. The size in bytes of each mask is reflected
+ *     by the reserved page header field 'nasids_size'. (Local partition's
+ *     mask pointers are xpc_part_nasids and xpc_mach_nasids.)
+ *
+ *   vars
+ *   vars part
+ *
+ *     Immediately following the mach_nasids mask are the XPC variables
+ *     required by other partitions. First are those that are generic to all
+ *     partitions (vars), followed on the next available cacheline by those
+ *     which are partition specific (vars part). These are setup by XPC.
+ *     (Local partition's vars pointers are xpc_vars and xpc_vars_part.)
+ *
+ * Note: Until vars_pa is set, the partition XPC code has not been initialized.
+ */
+struct xpc_rsvd_page {
+       u64 SAL_signature;      /* SAL: unique signature */
+       u64 SAL_version;        /* SAL: version */
+       u8 partid;              /* SAL: partition ID */
+       u8 version;
+       u8 pad1[6];             /* align to next u64 in cacheline */
+       volatile u64 vars_pa;
+       struct timespec stamp;  /* time when reserved page was setup by XPC */
+       u64 pad2[9];            /* align to last u64 in cacheline */
+       u64 nasids_size;        /* SAL: size of each nasid mask in bytes */
+};
+
+#define XPC_RP_VERSION _XPC_VERSION(1,1) /* version 1.1 of the reserved page */
+
+#define XPC_SUPPORTS_RP_STAMP(_version) \
+                       (_version >= _XPC_VERSION(1,1))
+
+/*
+ * compare stamps - the return value is:
+ *
+ *     < 0,    if stamp1 < stamp2
+ *     = 0,    if stamp1 == stamp2
+ *     > 0,    if stamp1 > stamp2
+ */
+static inline int
+xpc_compare_stamps(struct timespec *stamp1, struct timespec *stamp2)
+{
+       int ret;
+
+
+       if ((ret = stamp1->tv_sec - stamp2->tv_sec) == 0) {
+               ret = stamp1->tv_nsec - stamp2->tv_nsec;
+       }
+       return ret;
+}
+
+
+/*
+ * Define the structures by which XPC variables can be exported to other
+ * partitions. (There are two: struct xpc_vars and struct xpc_vars_part)
+ */
+
+/*
+ * The following structure describes the partition generic variables
+ * needed by other partitions in order to properly initialize.
+ *
+ * struct xpc_vars version number also applies to struct xpc_vars_part.
+ * Changes to either structure and/or related functionality should be
+ * reflected by incrementing either the major or minor version numbers
+ * of struct xpc_vars.
+ */
+struct xpc_vars {
+       u8 version;
+       u64 heartbeat;
+       u64 heartbeating_to_mask;
+       u64 heartbeat_offline;  /* if 0, heartbeat should be changing */
+       int act_nasid;
+       int act_phys_cpuid;
+       u64 vars_part_pa;
+       u64 amos_page_pa;       /* paddr of page of AMOs from MSPEC driver */
+       AMO_t *amos_page;       /* vaddr of page of AMOs from MSPEC driver */
+};
+
+#define XPC_V_VERSION _XPC_VERSION(3,1) /* version 3.1 of the cross vars */
+
+#define XPC_SUPPORTS_DISENGAGE_REQUEST(_version) \
+                       (_version >= _XPC_VERSION(3,1))
+
+
+static inline int
+xpc_hb_allowed(partid_t partid, struct xpc_vars *vars)
+{
+       return ((vars->heartbeating_to_mask & (1UL << partid)) != 0);
+}
+
+static inline void
+xpc_allow_hb(partid_t partid, struct xpc_vars *vars)
+{
+       u64 old_mask, new_mask;
+
+       do {
+               old_mask = vars->heartbeating_to_mask;
+               new_mask = (old_mask | (1UL << partid));
+       } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) !=
+                                                       old_mask);
+}
+
+static inline void
+xpc_disallow_hb(partid_t partid, struct xpc_vars *vars)
+{
+       u64 old_mask, new_mask;
+
+       do {
+               old_mask = vars->heartbeating_to_mask;
+               new_mask = (old_mask & ~(1UL << partid));
+       } while (cmpxchg(&vars->heartbeating_to_mask, old_mask, new_mask) !=
+                                                       old_mask);
+}
+
+
+/*
+ * The AMOs page consists of a number of AMO variables which are divided into
+ * four groups, The first two groups are used to identify an IRQ's sender.
+ * These two groups consist of 64 and 128 AMO variables respectively. The last
+ * two groups, consisting of just one AMO variable each, are used to identify
+ * the remote partitions that are currently engaged (from the viewpoint of
+ * the XPC running on the remote partition).
+ */
+#define XPC_NOTIFY_IRQ_AMOS       0
+#define XPC_ACTIVATE_IRQ_AMOS     (XPC_NOTIFY_IRQ_AMOS + XP_MAX_PARTITIONS)
+#define XPC_ENGAGED_PARTITIONS_AMO (XPC_ACTIVATE_IRQ_AMOS + XP_NASID_MASK_WORDS)
+#define XPC_DISENGAGE_REQUEST_AMO  (XPC_ENGAGED_PARTITIONS_AMO + 1)
+
+
+/*
+ * The following structure describes the per partition specific variables.
+ *
+ * An array of these structures, one per partition, will be defined. As a
+ * partition becomes active XPC will copy the array entry corresponding to
+ * itself from that partition. It is desirable that the size of this
+ * structure evenly divide into a cacheline, such that none of the entries
+ * in this array crosses a cacheline boundary. As it is now, each entry
+ * occupies half a cacheline.
+ */
+struct xpc_vars_part {
+       volatile u64 magic;
+
+       u64 openclose_args_pa;  /* physical address of open and close args */
+       u64 GPs_pa;             /* physical address of Get/Put values */
+
+       u64 IPI_amo_pa;         /* physical address of IPI AMO_t structure */
+       int IPI_nasid;          /* nasid of where to send IPIs */
+       int IPI_phys_cpuid;     /* physical CPU ID of where to send IPIs */
+
+       u8 nchannels;           /* #of defined channels supported */
+
+       u8 reserved[23];        /* pad to a full 64 bytes */
+};
+
+/*
+ * The vars_part MAGIC numbers play a part in the first contact protocol.
+ *
+ * MAGIC1 indicates that the per partition specific variables for a remote
+ * partition have been initialized by this partition.
+ *
+ * MAGIC2 indicates that this partition has pulled the remote partititions
+ * per partition variables that pertain to this partition.
+ */
+#define XPC_VP_MAGIC1  0x0053524156435058L  /* 'XPCVARS\0'L (little endian) */
+#define XPC_VP_MAGIC2  0x0073726176435058L  /* 'XPCvars\0'L (little endian) */
+
+
+/* the reserved page sizes and offsets */
+
+#define XPC_RP_HEADER_SIZE     L1_CACHE_ALIGN(sizeof(struct xpc_rsvd_page))
+#define XPC_RP_VARS_SIZE       L1_CACHE_ALIGN(sizeof(struct xpc_vars))
+
+#define XPC_RP_PART_NASIDS(_rp) (u64 *) ((u8 *) _rp + XPC_RP_HEADER_SIZE)
+#define XPC_RP_MACH_NASIDS(_rp) (XPC_RP_PART_NASIDS(_rp) + xp_nasid_mask_words)
+#define XPC_RP_VARS(_rp)       ((struct xpc_vars *) XPC_RP_MACH_NASIDS(_rp) + xp_nasid_mask_words)
+#define XPC_RP_VARS_PART(_rp)  (struct xpc_vars_part *) ((u8 *) XPC_RP_VARS(rp) + XPC_RP_VARS_SIZE)
+
+
+/*
+ * Functions registered by add_timer() or called by kernel_thread() only
+ * allow for a single 64-bit argument. The following macros can be used to
+ * pack and unpack two (32-bit, 16-bit or 8-bit) arguments into or out from
+ * the passed argument.
+ */
+#define XPC_PACK_ARGS(_arg1, _arg2) \
+                       ((((u64) _arg1) & 0xffffffff) | \
+                       ((((u64) _arg2) & 0xffffffff) << 32))
+
+#define XPC_UNPACK_ARG1(_args) (((u64) _args) & 0xffffffff)
+#define XPC_UNPACK_ARG2(_args) ((((u64) _args) >> 32) & 0xffffffff)
+
+
+
+/*
+ * Define a Get/Put value pair (pointers) used with a message queue.
+ */
+struct xpc_gp {
+       volatile s64 get;       /* Get value */
+       volatile s64 put;       /* Put value */
+};
+
+#define XPC_GP_SIZE \
+               L1_CACHE_ALIGN(sizeof(struct xpc_gp) * XPC_NCHANNELS)
+
+
+
+/*
+ * Define a structure that contains arguments associated with opening and
+ * closing a channel.
+ */
+struct xpc_openclose_args {
+       u16 reason;             /* reason why channel is closing */
+       u16 msg_size;           /* sizeof each message entry */
+       u16 remote_nentries;    /* #of message entries in remote msg queue */
+       u16 local_nentries;     /* #of message entries in local msg queue */
+       u64 local_msgqueue_pa;  /* physical address of local message queue */
+};
+
+#define XPC_OPENCLOSE_ARGS_SIZE \
+             L1_CACHE_ALIGN(sizeof(struct xpc_openclose_args) * XPC_NCHANNELS)
+
+
+
+/* struct xpc_msg flags */
+
+#define        XPC_M_DONE              0x01    /* msg has been received/consumed */
+#define        XPC_M_READY             0x02    /* msg is ready to be sent */
+#define        XPC_M_INTERRUPT         0x04    /* send interrupt when msg consumed */
+
+
+#define XPC_MSG_ADDRESS(_payload) \
+               ((struct xpc_msg *)((u8 *)(_payload) - XPC_MSG_PAYLOAD_OFFSET))
+
+
+
+/*
+ * Defines notify entry.
+ *
+ * This is used to notify a message's sender that their message was received
+ * and consumed by the intended recipient.
+ */
+struct xpc_notify {
+       struct semaphore sema;          /* notify semaphore */
+       volatile u8 type;                       /* type of notification */
+
+       /* the following two fields are only used if type == XPC_N_CALL */
+       xpc_notify_func func;           /* user's notify function */
+       void *key;                      /* pointer to user's key */
+};
+
+/* struct xpc_notify type of notification */
+
+#define        XPC_N_CALL              0x01    /* notify function provided by user */
+
+
+
+/*
+ * Define the structure that manages all the stuff required by a channel. In
+ * particular, they are used to manage the messages sent across the channel.
+ *
+ * This structure is private to a partition, and is NOT shared across the
+ * partition boundary.
+ *
+ * There is an array of these structures for each remote partition. It is
+ * allocated at the time a partition becomes active. The array contains one
+ * of these structures for each potential channel connection to that partition.
+ *
+ * Each of these structures manages two message queues (circular buffers).
+ * They are allocated at the time a channel connection is made. One of
+ * these message queues (local_msgqueue) holds the locally created messages
+ * that are destined for the remote partition. The other of these message
+ * queues (remote_msgqueue) is a locally cached copy of the remote partition's
+ * own local_msgqueue.
+ *
+ * The following is a description of the Get/Put pointers used to manage these
+ * two message queues. Consider the local_msgqueue to be on one partition
+ * and the remote_msgqueue to be its cached copy on another partition. A
+ * description of what each of the lettered areas contains is included.
+ *
+ *
+ *                     local_msgqueue      remote_msgqueue
+ *
+ *                        |/////////|      |/////////|
+ *    w_remote_GP.get --> +---------+      |/////////|
+ *                        |    F    |      |/////////|
+ *     remote_GP.get  --> +---------+      +---------+ <-- local_GP->get
+ *                        |         |      |         |
+ *                        |         |      |    E    |
+ *                        |         |      |         |
+ *                        |         |      +---------+ <-- w_local_GP.get
+ *                        |    B    |      |/////////|
+ *                        |         |      |////D////|
+ *                        |         |      |/////////|
+ *                        |         |      +---------+ <-- w_remote_GP.put
+ *                        |         |      |////C////|
+ *      local_GP->put --> +---------+      +---------+ <-- remote_GP.put
+ *                        |         |      |/////////|
+ *                        |    A    |      |/////////|
+ *                        |         |      |/////////|
+ *     w_local_GP.put --> +---------+      |/////////|
+ *                        |/////////|      |/////////|
+ *
+ *
+ *         ( remote_GP.[get|put] are cached copies of the remote
+ *           partition's local_GP->[get|put], and thus their values can
+ *           lag behind their counterparts on the remote partition. )
+ *
+ *
+ *  A - Messages that have been allocated, but have not yet been sent to the
+ *     remote partition.
+ *
+ *  B - Messages that have been sent, but have not yet been acknowledged by the
+ *      remote partition as having been received.
+ *
+ *  C - Area that needs to be prepared for the copying of sent messages, by
+ *     the clearing of the message flags of any previously received messages.
+ *
+ *  D - Area into which sent messages are to be copied from the remote
+ *     partition's local_msgqueue and then delivered to their intended
+ *     recipients. [ To allow for a multi-message copy, another pointer
+ *     (next_msg_to_pull) has been added to keep track of the next message
+ *     number needing to be copied (pulled). It chases after w_remote_GP.put.
+ *     Any messages lying between w_local_GP.get and next_msg_to_pull have
+ *     been copied and are ready to be delivered. ]
+ *
+ *  E - Messages that have been copied and delivered, but have not yet been
+ *     acknowledged by the recipient as having been received.
+ *
+ *  F - Messages that have been acknowledged, but XPC has not yet notified the
+ *     sender that the message was received by its intended recipient.
+ *     This is also an area that needs to be prepared for the allocating of
+ *     new messages, by the clearing of the message flags of the acknowledged
+ *     messages.
+ */
+struct xpc_channel {
+       partid_t partid;                /* ID of remote partition connected */
+       spinlock_t lock;                /* lock for updating this structure */
+       u32 flags;                      /* general flags */
+
+       enum xpc_retval reason;         /* reason why channel is disconnect'g */
+       int reason_line;                /* line# disconnect initiated from */
+
+       u16 number;                     /* channel # */
+
+       u16 msg_size;                   /* sizeof each msg entry */
+       u16 local_nentries;             /* #of msg entries in local msg queue */
+       u16 remote_nentries;            /* #of msg entries in remote msg queue*/
+
+       void *local_msgqueue_base;      /* base address of kmalloc'd space */
+       struct xpc_msg *local_msgqueue; /* local message queue */
+       void *remote_msgqueue_base;     /* base address of kmalloc'd space */
+       struct xpc_msg *remote_msgqueue;/* cached copy of remote partition's */
+                                       /* local message queue */
+       u64 remote_msgqueue_pa;         /* phys addr of remote partition's */
+                                       /* local message queue */
+
+       atomic_t references;            /* #of external references to queues */
+
+       atomic_t n_on_msg_allocate_wq;   /* #on msg allocation wait queue */
+       wait_queue_head_t msg_allocate_wq; /* msg allocation wait queue */
+
+       u8 delayed_IPI_flags;           /* IPI flags received, but delayed */
+                                       /* action until channel disconnected */
+
+       /* queue of msg senders who want to be notified when msg received */
+
+       atomic_t n_to_notify;           /* #of msg senders to notify */
+       struct xpc_notify *notify_queue;/* notify queue for messages sent */
+
+       xpc_channel_func func;          /* user's channel function */
+       void *key;                      /* pointer to user's key */
+
+       struct semaphore msg_to_pull_sema; /* next msg to pull serialization */
+       struct semaphore wdisconnect_sema; /* wait for channel disconnect */
+
+       struct xpc_openclose_args *local_openclose_args; /* args passed on */
+                                       /* opening or closing of channel */
+
+       /* various flavors of local and remote Get/Put values */
+
+       struct xpc_gp *local_GP;        /* local Get/Put values */
+       struct xpc_gp remote_GP;        /* remote Get/Put values */
+       struct xpc_gp w_local_GP;       /* working local Get/Put values */
+       struct xpc_gp w_remote_GP;      /* working remote Get/Put values */
+       s64 next_msg_to_pull;           /* Put value of next msg to pull */
+
+       /* kthread management related fields */
+
+// >>> rethink having kthreads_assigned_limit and kthreads_idle_limit; perhaps
+// >>> allow the assigned limit be unbounded and let the idle limit be dynamic
+// >>> dependent on activity over the last interval of time
+       atomic_t kthreads_assigned;     /* #of kthreads assigned to channel */
+       u32 kthreads_assigned_limit;    /* limit on #of kthreads assigned */
+       atomic_t kthreads_idle;         /* #of kthreads idle waiting for work */
+       u32 kthreads_idle_limit;        /* limit on #of kthreads idle */
+       atomic_t kthreads_active;       /* #of kthreads actively working */
+       // >>> following field is temporary
+       u32 kthreads_created;           /* total #of kthreads created */
+
+       wait_queue_head_t idle_wq;      /* idle kthread wait queue */
+
+} ____cacheline_aligned;
+
+
+/* struct xpc_channel flags */
+
+#define        XPC_C_WASCONNECTED      0x00000001 /* channel was connected */
+
+#define        XPC_C_ROPENREPLY        0x00000002 /* remote open channel reply */
+#define        XPC_C_OPENREPLY         0x00000004 /* local open channel reply */
+#define        XPC_C_ROPENREQUEST      0x00000008 /* remote open channel request */
+#define        XPC_C_OPENREQUEST       0x00000010 /* local open channel request */
+
+#define        XPC_C_SETUP             0x00000020 /* channel's msgqueues are alloc'd */
+#define        XPC_C_CONNECTCALLOUT    0x00000040 /* channel connected callout made */
+#define        XPC_C_CONNECTED         0x00000080 /* local channel is connected */
+#define        XPC_C_CONNECTING        0x00000100 /* channel is being connected */
+
+#define        XPC_C_RCLOSEREPLY       0x00000200 /* remote close channel reply */
+#define        XPC_C_CLOSEREPLY        0x00000400 /* local close channel reply */
+#define        XPC_C_RCLOSEREQUEST     0x00000800 /* remote close channel request */
+#define        XPC_C_CLOSEREQUEST      0x00001000 /* local close channel request */
+
+#define        XPC_C_DISCONNECTED      0x00002000 /* channel is disconnected */
+#define        XPC_C_DISCONNECTING     0x00004000 /* channel is being disconnected */
+#define        XPC_C_DISCONNECTCALLOUT 0x00008000 /* chan disconnected callout made */
+#define        XPC_C_WDISCONNECT       0x00010000 /* waiting for channel disconnect */
+
+
+
+/*
+ * Manages channels on a partition basis. There is one of these structures
+ * for each partition (a partition will never utilize the structure that
+ * represents itself).
+ */
+struct xpc_partition {
+
+       /* XPC HB infrastructure */
+
+       u8 remote_rp_version;           /* version# of partition's rsvd pg */
+       struct timespec remote_rp_stamp;/* time when rsvd pg was initialized */
+       u64 remote_rp_pa;               /* phys addr of partition's rsvd pg */
+       u64 remote_vars_pa;             /* phys addr of partition's vars */
+       u64 remote_vars_part_pa;        /* phys addr of partition's vars part */
+       u64 last_heartbeat;             /* HB at last read */
+       u64 remote_amos_page_pa;        /* phys addr of partition's amos page */
+       int remote_act_nasid;           /* active part's act/deact nasid */
+       int remote_act_phys_cpuid;      /* active part's act/deact phys cpuid */
+       u32 act_IRQ_rcvd;               /* IRQs since activation */
+       spinlock_t act_lock;            /* protect updating of act_state */
+       u8 act_state;                   /* from XPC HB viewpoint */
+       u8 remote_vars_version;         /* version# of partition's vars */
+       enum xpc_retval reason;         /* reason partition is deactivating */
+       int reason_line;                /* line# deactivation initiated from */
+       int reactivate_nasid;           /* nasid in partition to reactivate */
+
+       unsigned long disengage_request_timeout; /* timeout in jiffies */
+       struct timer_list disengage_request_timer;
+
+
+       /* XPC infrastructure referencing and teardown control */
+
+       volatile u8 setup_state;        /* infrastructure setup state */
+       wait_queue_head_t teardown_wq;  /* kthread waiting to teardown infra */
+       atomic_t references;            /* #of references to infrastructure */
+
+
+       /*
+        * NONE OF THE PRECEDING FIELDS OF THIS STRUCTURE WILL BE CLEARED WHEN
+        * XPC SETS UP THE NECESSARY INFRASTRUCTURE TO SUPPORT CROSS PARTITION
+        * COMMUNICATION. ALL OF THE FOLLOWING FIELDS WILL BE CLEARED. (THE
+        * 'nchannels' FIELD MUST BE THE FIRST OF THE FIELDS TO BE CLEARED.)
+        */
+
+
+       u8 nchannels;              /* #of defined channels supported */
+       atomic_t nchannels_active; /* #of channels that are not DISCONNECTED */
+       atomic_t nchannels_engaged;/* #of channels engaged with remote part */
+       struct xpc_channel *channels;/* array of channel structures */
+
+       void *local_GPs_base;     /* base address of kmalloc'd space */
+       struct xpc_gp *local_GPs; /* local Get/Put values */
+       void *remote_GPs_base;    /* base address of kmalloc'd space */
+       struct xpc_gp *remote_GPs;/* copy of remote partition's local Get/Put */
+                                 /* values */
+       u64 remote_GPs_pa;        /* phys address of remote partition's local */
+                                 /* Get/Put values */
+
+
+       /* fields used to pass args when opening or closing a channel */
+
+       void *local_openclose_args_base;  /* base address of kmalloc'd space */
+       struct xpc_openclose_args *local_openclose_args;  /* local's args */
+       void *remote_openclose_args_base; /* base address of kmalloc'd space */
+       struct xpc_openclose_args *remote_openclose_args; /* copy of remote's */
+                                         /* args */
+       u64 remote_openclose_args_pa;     /* phys addr of remote's args */
+
+
+       /* IPI sending, receiving and handling related fields */
+
+       int remote_IPI_nasid;       /* nasid of where to send IPIs */
+       int remote_IPI_phys_cpuid;  /* phys CPU ID of where to send IPIs */
+       AMO_t *remote_IPI_amo_va;   /* address of remote IPI AMO_t structure */
+
+       AMO_t *local_IPI_amo_va;    /* address of IPI AMO_t structure */
+       u64 local_IPI_amo;          /* IPI amo flags yet to be handled */
+       char IPI_owner[8];          /* IPI owner's name */
+       struct timer_list dropped_IPI_timer; /* dropped IPI timer */
+
+       spinlock_t IPI_lock;        /* IPI handler lock */
+
+
+       /* channel manager related fields */
+
+       atomic_t channel_mgr_requests;  /* #of requests to activate chan mgr */
+       wait_queue_head_t channel_mgr_wq; /* channel mgr's wait queue */
+
+} ____cacheline_aligned;
+
+
+/* struct xpc_partition act_state values (for XPC HB) */
+
+#define        XPC_P_INACTIVE          0x00    /* partition is not active */
+#define XPC_P_ACTIVATION_REQ   0x01    /* created thread to activate */
+#define XPC_P_ACTIVATING       0x02    /* activation thread started */
+#define XPC_P_ACTIVE           0x03    /* xpc_partition_up() was called */
+#define XPC_P_DEACTIVATING     0x04    /* partition deactivation initiated */
+
+
+#define XPC_DEACTIVATE_PARTITION(_p, _reason) \
+                       xpc_deactivate_partition(__LINE__, (_p), (_reason))
+
+
+/* struct xpc_partition setup_state values */
+
+#define XPC_P_UNSET            0x00    /* infrastructure was never setup */
+#define XPC_P_SETUP            0x01    /* infrastructure is setup */
+#define XPC_P_WTEARDOWN                0x02    /* waiting to teardown infrastructure */
+#define XPC_P_TORNDOWN         0x03    /* infrastructure is torndown */
+
+
+
+/*
+ * struct xpc_partition IPI_timer #of seconds to wait before checking for
+ * dropped IPIs. These occur whenever an IPI amo write doesn't complete until
+ * after the IPI was received.
+ */
+#define XPC_P_DROPPED_IPI_WAIT (0.25 * HZ)
+
+
+/* number of seconds to wait for other partitions to disengage */
+#define XPC_DISENGAGE_REQUEST_DEFAULT_TIMELIMIT        90
+
+/* interval in seconds to print 'waiting disengagement' messages */
+#define XPC_DISENGAGE_PRINTMSG_INTERVAL                10
+
+
+#define XPC_PARTID(_p) ((partid_t) ((_p) - &xpc_partitions[0]))
+
+
+
+/* found in xp_main.c */
+extern struct xpc_registration xpc_registrations[];
+
+
+/* found in xpc_main.c */
+extern struct device *xpc_part;
+extern struct device *xpc_chan;
+extern int xpc_disengage_request_timelimit;
+extern int xpc_disengage_request_timedout;
+extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *);
+extern void xpc_dropped_IPI_check(struct xpc_partition *);
+extern void xpc_activate_partition(struct xpc_partition *);
+extern void xpc_activate_kthreads(struct xpc_channel *, int);
+extern void xpc_create_kthreads(struct xpc_channel *, int);
+extern void xpc_disconnect_wait(int);
+
+
+/* found in xpc_partition.c */
+extern int xpc_exiting;
+extern struct xpc_vars *xpc_vars;
+extern struct xpc_rsvd_page *xpc_rsvd_page;
+extern struct xpc_vars_part *xpc_vars_part;
+extern struct xpc_partition xpc_partitions[XP_MAX_PARTITIONS + 1];
+extern char xpc_remote_copy_buffer[];
+extern struct xpc_rsvd_page *xpc_rsvd_page_init(void);
+extern void xpc_allow_IPI_ops(void);
+extern void xpc_restrict_IPI_ops(void);
+extern int xpc_identify_act_IRQ_sender(void);
+extern int xpc_partition_disengaged(struct xpc_partition *);
+extern enum xpc_retval xpc_mark_partition_active(struct xpc_partition *);
+extern void xpc_mark_partition_inactive(struct xpc_partition *);
+extern void xpc_discovery(void);
+extern void xpc_check_remote_hb(void);
+extern void xpc_deactivate_partition(const int, struct xpc_partition *,
+                                               enum xpc_retval);
+extern enum xpc_retval xpc_initiate_partid_to_nasids(partid_t, void *);
+
+
+/* found in xpc_channel.c */
+extern void xpc_initiate_connect(int);
+extern void xpc_initiate_disconnect(int);
+extern enum xpc_retval xpc_initiate_allocate(partid_t, int, u32, void **);
+extern enum xpc_retval xpc_initiate_send(partid_t, int, void *);
+extern enum xpc_retval xpc_initiate_send_notify(partid_t, int, void *,
+                                               xpc_notify_func, void *);
+extern void xpc_initiate_received(partid_t, int, void *);
+extern enum xpc_retval xpc_setup_infrastructure(struct xpc_partition *);
+extern enum xpc_retval xpc_pull_remote_vars_part(struct xpc_partition *);
+extern void xpc_process_channel_activity(struct xpc_partition *);
+extern void xpc_connected_callout(struct xpc_channel *);
+extern void xpc_deliver_msg(struct xpc_channel *);
+extern void xpc_disconnect_channel(const int, struct xpc_channel *,
+                                       enum xpc_retval, unsigned long *);
+extern void xpc_disconnect_callout(struct xpc_channel *, enum xpc_retval);
+extern void xpc_partition_going_down(struct xpc_partition *, enum xpc_retval);
+extern void xpc_teardown_infrastructure(struct xpc_partition *);
+
+
+
+static inline void
+xpc_wakeup_channel_mgr(struct xpc_partition *part)
+{
+       if (atomic_inc_return(&part->channel_mgr_requests) == 1) {
+               wake_up(&part->channel_mgr_wq);
+       }
+}
+
+
+
+/*
+ * These next two inlines are used to keep us from tearing down a channel's
+ * msg queues while a thread may be referencing them.
+ */
+static inline void
+xpc_msgqueue_ref(struct xpc_channel *ch)
+{
+       atomic_inc(&ch->references);
+}
+
+static inline void
+xpc_msgqueue_deref(struct xpc_channel *ch)
+{
+       s32 refs = atomic_dec_return(&ch->references);
+
+       DBUG_ON(refs < 0);
+       if (refs == 0) {
+               xpc_wakeup_channel_mgr(&xpc_partitions[ch->partid]);
+       }
+}
+
+
+
+#define XPC_DISCONNECT_CHANNEL(_ch, _reason, _irqflgs) \
+               xpc_disconnect_channel(__LINE__, _ch, _reason, _irqflgs)
+
+
+/*
+ * These two inlines are used to keep us from tearing down a partition's
+ * setup infrastructure while a thread may be referencing it.
+ */
+static inline void
+xpc_part_deref(struct xpc_partition *part)
+{
+       s32 refs = atomic_dec_return(&part->references);
+
+
+       DBUG_ON(refs < 0);
+       if (refs == 0 && part->setup_state == XPC_P_WTEARDOWN) {
+               wake_up(&part->teardown_wq);
+       }
+}
+
+static inline int
+xpc_part_ref(struct xpc_partition *part)
+{
+       int setup;
+
+
+       atomic_inc(&part->references);
+       setup = (part->setup_state == XPC_P_SETUP);
+       if (!setup) {
+               xpc_part_deref(part);
+       }
+       return setup;
+}
+
+
+
+/*
+ * The following macro is to be used for the setting of the reason and
+ * reason_line fields in both the struct xpc_channel and struct xpc_partition
+ * structures.
+ */
+#define XPC_SET_REASON(_p, _reason, _line) \
+       { \
+               (_p)->reason = _reason; \
+               (_p)->reason_line = _line; \
+       }
+
+
+
+/*
+ * This next set of inlines are used to keep track of when a partition is
+ * potentially engaged in accessing memory belonging to another partition.
+ */
+
+static inline void
+xpc_mark_partition_engaged(struct xpc_partition *part)
+{
+       unsigned long irq_flags;
+       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
+                               (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t)));
+
+
+       local_irq_save(irq_flags);
+
+       /* set bit corresponding to our partid in remote partition's AMO */
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR,
+                                               (1UL << sn_partition_id));
+       /*
+        * We must always use the nofault function regardless of whether we
+        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
+        * didn't, we'd never know that the other partition is down and would
+        * keep sending IPIs and AMOs to it until the heartbeat times out.
+        */
+       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
+                               variable), xp_nofault_PIOR_target));
+
+       local_irq_restore(irq_flags);
+}
+
+static inline void
+xpc_mark_partition_disengaged(struct xpc_partition *part)
+{
+       unsigned long irq_flags;
+       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
+                               (XPC_ENGAGED_PARTITIONS_AMO * sizeof(AMO_t)));
+
+
+       local_irq_save(irq_flags);
+
+       /* clear bit corresponding to our partid in remote partition's AMO */
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
+                                               ~(1UL << sn_partition_id));
+       /*
+        * We must always use the nofault function regardless of whether we
+        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
+        * didn't, we'd never know that the other partition is down and would
+        * keep sending IPIs and AMOs to it until the heartbeat times out.
+        */
+       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
+                               variable), xp_nofault_PIOR_target));
+
+       local_irq_restore(irq_flags);
+}
+
+static inline void
+xpc_request_partition_disengage(struct xpc_partition *part)
+{
+       unsigned long irq_flags;
+       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
+                               (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t)));
+
+
+       local_irq_save(irq_flags);
+
+       /* set bit corresponding to our partid in remote partition's AMO */
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR,
+                                               (1UL << sn_partition_id));
+       /*
+        * We must always use the nofault function regardless of whether we
+        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
+        * didn't, we'd never know that the other partition is down and would
+        * keep sending IPIs and AMOs to it until the heartbeat times out.
+        */
+       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
+                               variable), xp_nofault_PIOR_target));
+
+       local_irq_restore(irq_flags);
+}
+
+static inline void
+xpc_cancel_partition_disengage_request(struct xpc_partition *part)
+{
+       unsigned long irq_flags;
+       AMO_t *amo = (AMO_t *) __va(part->remote_amos_page_pa +
+                               (XPC_DISENGAGE_REQUEST_AMO * sizeof(AMO_t)));
+
+
+       local_irq_save(irq_flags);
+
+       /* clear bit corresponding to our partid in remote partition's AMO */
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
+                                               ~(1UL << sn_partition_id));
+       /*
+        * We must always use the nofault function regardless of whether we
+        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
+        * didn't, we'd never know that the other partition is down and would
+        * keep sending IPIs and AMOs to it until the heartbeat times out.
+        */
+       (void) xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->
+                               variable), xp_nofault_PIOR_target));
+
+       local_irq_restore(irq_flags);
+}
+
+static inline u64
+xpc_partition_engaged(u64 partid_mask)
+{
+       AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO;
+
+
+       /* return our partition's AMO variable ANDed with partid_mask */
+       return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) &
+                                                               partid_mask);
+}
+
+static inline u64
+xpc_partition_disengage_requested(u64 partid_mask)
+{
+       AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO;
+
+
+       /* return our partition's AMO variable ANDed with partid_mask */
+       return (FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_LOAD) &
+                                                               partid_mask);
+}
+
+static inline void
+xpc_clear_partition_engaged(u64 partid_mask)
+{
+       AMO_t *amo = xpc_vars->amos_page + XPC_ENGAGED_PARTITIONS_AMO;
+
+
+       /* clear bit(s) based on partid_mask in our partition's AMO */
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
+                                                               ~partid_mask);
+}
+
+static inline void
+xpc_clear_partition_disengage_request(u64 partid_mask)
+{
+       AMO_t *amo = xpc_vars->amos_page + XPC_DISENGAGE_REQUEST_AMO;
+
+
+       /* clear bit(s) based on partid_mask in our partition's AMO */
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_AND,
+                                                               ~partid_mask);
+}
+
+
+
+/*
+ * The following set of macros and inlines are used for the sending and
+ * receiving of IPIs (also known as IRQs). There are two flavors of IPIs,
+ * one that is associated with partition activity (SGI_XPC_ACTIVATE) and
+ * the other that is associated with channel activity (SGI_XPC_NOTIFY).
+ */
+
+static inline u64
+xpc_IPI_receive(AMO_t *amo)
+{
+       return FETCHOP_LOAD_OP(TO_AMO((u64) &amo->variable), FETCHOP_CLEAR);
+}
+
+
+static inline enum xpc_retval
+xpc_IPI_send(AMO_t *amo, u64 flag, int nasid, int phys_cpuid, int vector)
+{
+       int ret = 0;
+       unsigned long irq_flags;
+
+
+       local_irq_save(irq_flags);
+
+       FETCHOP_STORE_OP(TO_AMO((u64) &amo->variable), FETCHOP_OR, flag);
+       sn_send_IPI_phys(nasid, phys_cpuid, vector, 0);
+
+       /*
+        * We must always use the nofault function regardless of whether we
+        * are on a Shub 1.1 system or a Shub 1.2 slice 0xc processor. If we
+        * didn't, we'd never know that the other partition is down and would
+        * keep sending IPIs and AMOs to it until the heartbeat times out.
+        */
+       ret = xp_nofault_PIOR((u64 *) GLOBAL_MMR_ADDR(NASID_GET(&amo->variable),
+                               xp_nofault_PIOR_target));
+
+       local_irq_restore(irq_flags);
+
+       return ((ret == 0) ? xpcSuccess : xpcPioReadError);
+}
+
+
+/*
+ * IPIs associated with SGI_XPC_ACTIVATE IRQ.
+ */
+
+/*
+ * Flag the appropriate AMO variable and send an IPI to the specified node.
+ */
+static inline void
+xpc_activate_IRQ_send(u64 amos_page_pa, int from_nasid, int to_nasid,
+                       int to_phys_cpuid)
+{
+       int w_index = XPC_NASID_W_INDEX(from_nasid);
+       int b_index = XPC_NASID_B_INDEX(from_nasid);
+       AMO_t *amos = (AMO_t *) __va(amos_page_pa +
+                               (XPC_ACTIVATE_IRQ_AMOS * sizeof(AMO_t)));
+
+
+       (void) xpc_IPI_send(&amos[w_index], (1UL << b_index), to_nasid,
+                               to_phys_cpuid, SGI_XPC_ACTIVATE);
+}
+
+static inline void
+xpc_IPI_send_activate(struct xpc_vars *vars)
+{
+       xpc_activate_IRQ_send(vars->amos_page_pa, cnodeid_to_nasid(0),
+                               vars->act_nasid, vars->act_phys_cpuid);
+}
+
+static inline void
+xpc_IPI_send_activated(struct xpc_partition *part)
+{
+       xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
+                       part->remote_act_nasid, part->remote_act_phys_cpuid);
+}
+
+static inline void
+xpc_IPI_send_reactivate(struct xpc_partition *part)
+{
+       xpc_activate_IRQ_send(xpc_vars->amos_page_pa, part->reactivate_nasid,
+                               xpc_vars->act_nasid, xpc_vars->act_phys_cpuid);
+}
+
+static inline void
+xpc_IPI_send_disengage(struct xpc_partition *part)
+{
+       xpc_activate_IRQ_send(part->remote_amos_page_pa, cnodeid_to_nasid(0),
+                       part->remote_act_nasid, part->remote_act_phys_cpuid);
+}
+
+
+/*
+ * IPIs associated with SGI_XPC_NOTIFY IRQ.
+ */
+
+/*
+ * Send an IPI to the remote partition that is associated with the
+ * specified channel.
+ */
+#define XPC_NOTIFY_IRQ_SEND(_ch, _ipi_f, _irq_f) \
+               xpc_notify_IRQ_send(_ch, _ipi_f, #_ipi_f, _irq_f)
+
+static inline void
+xpc_notify_IRQ_send(struct xpc_channel *ch, u8 ipi_flag, char *ipi_flag_string,
+                       unsigned long *irq_flags)
+{
+       struct xpc_partition *part = &xpc_partitions[ch->partid];
+       enum xpc_retval ret;
+
+
+       if (likely(part->act_state != XPC_P_DEACTIVATING)) {
+               ret = xpc_IPI_send(part->remote_IPI_amo_va,
+                                       (u64) ipi_flag << (ch->number * 8),
+                                       part->remote_IPI_nasid,
+                                       part->remote_IPI_phys_cpuid,
+                                       SGI_XPC_NOTIFY);
+               dev_dbg(xpc_chan, "%s sent to partid=%d, channel=%d, ret=%d\n",
+                       ipi_flag_string, ch->partid, ch->number, ret);
+               if (unlikely(ret != xpcSuccess)) {
+                       if (irq_flags != NULL) {
+                               spin_unlock_irqrestore(&ch->lock, *irq_flags);
+                       }
+                       XPC_DEACTIVATE_PARTITION(part, ret);
+                       if (irq_flags != NULL) {
+                               spin_lock_irqsave(&ch->lock, *irq_flags);
+                       }
+               }
+       }
+}
+
+
+/*
+ * Make it look like the remote partition, which is associated with the
+ * specified channel, sent us an IPI. This faked IPI will be handled
+ * by xpc_dropped_IPI_check().
+ */
+#define XPC_NOTIFY_IRQ_SEND_LOCAL(_ch, _ipi_f) \
+               xpc_notify_IRQ_send_local(_ch, _ipi_f, #_ipi_f)
+
+static inline void
+xpc_notify_IRQ_send_local(struct xpc_channel *ch, u8 ipi_flag,
+                               char *ipi_flag_string)
+{
+       struct xpc_partition *part = &xpc_partitions[ch->partid];
+
+
+       FETCHOP_STORE_OP(TO_AMO((u64) &part->local_IPI_amo_va->variable),
+                       FETCHOP_OR, ((u64) ipi_flag << (ch->number * 8)));
+       dev_dbg(xpc_chan, "%s sent local from partid=%d, channel=%d\n",
+               ipi_flag_string, ch->partid, ch->number);
+}
+
+
+/*
+ * The sending and receiving of IPIs includes the setting of an AMO variable
+ * to indicate the reason the IPI was sent. The 64-bit variable is divided
+ * up into eight bytes, ordered from right to left. Byte zero pertains to
+ * channel 0, byte one to channel 1, and so on. Each byte is described by
+ * the following IPI flags.
+ */
+
+#define        XPC_IPI_CLOSEREQUEST    0x01
+#define        XPC_IPI_CLOSEREPLY      0x02
+#define        XPC_IPI_OPENREQUEST     0x04
+#define        XPC_IPI_OPENREPLY       0x08
+#define        XPC_IPI_MSGREQUEST      0x10
+
+
+/* given an AMO variable and a channel#, get its associated IPI flags */
+#define XPC_GET_IPI_FLAGS(_amo, _c)    ((u8) (((_amo) >> ((_c) * 8)) & 0xff))
+#define XPC_SET_IPI_FLAGS(_amo, _c, _f)        (_amo) |= ((u64) (_f) << ((_c) * 8))
+
+#define        XPC_ANY_OPENCLOSE_IPI_FLAGS_SET(_amo) ((_amo) & 0x0f0f0f0f0f0f0f0f)
+#define XPC_ANY_MSG_IPI_FLAGS_SET(_amo)       ((_amo) & 0x1010101010101010)
+
+
+static inline void
+xpc_IPI_send_closerequest(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+       struct xpc_openclose_args *args = ch->local_openclose_args;
+
+
+       args->reason = ch->reason;
+
+       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREQUEST, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_closereply(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_CLOSEREPLY, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_openrequest(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+       struct xpc_openclose_args *args = ch->local_openclose_args;
+
+
+       args->msg_size = ch->msg_size;
+       args->local_nentries = ch->local_nentries;
+
+       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREQUEST, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_openreply(struct xpc_channel *ch, unsigned long *irq_flags)
+{
+       struct xpc_openclose_args *args = ch->local_openclose_args;
+
+
+       args->remote_nentries = ch->remote_nentries;
+       args->local_nentries = ch->local_nentries;
+       args->local_msgqueue_pa = __pa(ch->local_msgqueue);
+
+       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_OPENREPLY, irq_flags);
+}
+
+static inline void
+xpc_IPI_send_msgrequest(struct xpc_channel *ch)
+{
+       XPC_NOTIFY_IRQ_SEND(ch, XPC_IPI_MSGREQUEST, NULL);
+}
+
+static inline void
+xpc_IPI_send_local_msgrequest(struct xpc_channel *ch)
+{
+       XPC_NOTIFY_IRQ_SEND_LOCAL(ch, XPC_IPI_MSGREQUEST);
+}
+
+
+/*
+ * Memory for XPC's AMO variables is allocated by the MSPEC driver. These
+ * pages are located in the lowest granule. The lowest granule uses 4k pages
+ * for cached references and an alternate TLB handler to never provide a
+ * cacheable mapping for the entire region. This will prevent speculative
+ * reading of cached copies of our lines from being issued which will cause
+ * a PI FSB Protocol error to be generated by the SHUB. For XPC, we need 64
+ * AMO variables (based on XP_MAX_PARTITIONS) for message notification and an
+ * additional 128 AMO variables (based on XP_NASID_MASK_WORDS) for partition
+ * activation and 2 AMO variables for partition deactivation.
+ */
+static inline AMO_t *
+xpc_IPI_init(int index)
+{
+       AMO_t *amo = xpc_vars->amos_page + index;
+
+
+       (void) xpc_IPI_receive(amo);    /* clear AMO variable */
+       return amo;
+}
+
+
+
+static inline enum xpc_retval
+xpc_map_bte_errors(bte_result_t error)
+{
+       switch (error) {
+       case BTE_SUCCESS:       return xpcSuccess;
+       case BTEFAIL_DIR:       return xpcBteDirectoryError;
+       case BTEFAIL_POISON:    return xpcBtePoisonError;
+       case BTEFAIL_WERR:      return xpcBteWriteError;
+       case BTEFAIL_ACCESS:    return xpcBteAccessError;
+       case BTEFAIL_PWERR:     return xpcBtePWriteError;
+       case BTEFAIL_PRERR:     return xpcBtePReadError;
+       case BTEFAIL_TOUT:      return xpcBteTimeOutError;
+       case BTEFAIL_XTERR:     return xpcBteXtalkError;
+       case BTEFAIL_NOTAVAIL:  return xpcBteNotAvailable;
+       default:                return xpcBteUnmappedError;
+       }
+}
+
+
+
+static inline void *
+xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
+{
+       /* see if kmalloc will give us cachline aligned memory by default */
+       *base = kmalloc(size, flags);
+       if (*base == NULL) {
+               return NULL;
+       }
+       if ((u64) *base == L1_CACHE_ALIGN((u64) *base)) {
+               return *base;
+       }
+       kfree(*base);
+
+       /* nope, we'll have to do it ourselves */
+       *base = kmalloc(size + L1_CACHE_BYTES, flags);
+       if (*base == NULL) {
+               return NULL;
+       }
+       return (void *) L1_CACHE_ALIGN((u64) *base);
+}
+
+
+/*
+ * Check to see if there is any channel activity to/from the specified
+ * partition.
+ */
+static inline void
+xpc_check_for_channel_activity(struct xpc_partition *part)
+{
+       u64 IPI_amo;
+       unsigned long irq_flags;
+
+
+       IPI_amo = xpc_IPI_receive(part->local_IPI_amo_va);
+       if (IPI_amo == 0) {
+               return;
+       }
+
+       spin_lock_irqsave(&part->IPI_lock, irq_flags);
+       part->local_IPI_amo |= IPI_amo;
+       spin_unlock_irqrestore(&part->IPI_lock, irq_flags);
+
+       dev_dbg(xpc_chan, "received IPI from partid=%d, IPI_amo=0x%lx\n",
+               XPC_PARTID(part), IPI_amo);
+
+       xpc_wakeup_channel_mgr(part);
+}
+
+
+#endif /* _ASM_IA64_SN_XPC_H */
+
index 653bb7f9a7532dbd62841b6dfbdf28897039f2f5..1d6518fe1f024ddcaf7a563904af38149dc10e8b 100644 (file)
@@ -93,6 +93,7 @@ struct thread_info {
 #define TIF_POLLING_NRFLAG     16      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             17
 #define TIF_MCA_INIT           18      /* this task is processing MCA or INIT */
+#define TIF_DB_DISABLED                19      /* debug trap disabled for fsyscall */
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
@@ -100,9 +101,10 @@ struct thread_info {
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
-#define _TIF_SIGDELAYED        (1 << TIF_SIGDELAYED)
+#define _TIF_SIGDELAYED                (1 << TIF_SIGDELAYED)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_MCA_INIT          (1 << TIF_MCA_INIT)
+#define _TIF_DB_DISABLED       (1 << TIF_DB_DISABLED)
 
 /* "work to do on user-return" bits */
 #define TIF_ALLWORK_MASK       (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SIGDELAYED)
index 248f9aec959c69a93f43a6bc15ceb94e3bd90bc0..147a38dcc766ed20129a497080bbcb42cd1026b2 100644 (file)
@@ -36,7 +36,7 @@ static __inline__ int atomic_add_return(int a, atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%2         # atomic_add_return\n\
        add     %0,%1,%0\n"
        PPC405_ERR77(0,%2)
@@ -72,7 +72,7 @@ static __inline__ int atomic_sub_return(int a, atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%2         # atomic_sub_return\n\
        subf    %0,%1,%0\n"
        PPC405_ERR77(0,%2)
@@ -106,7 +106,7 @@ static __inline__ int atomic_inc_return(atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%1         # atomic_inc_return\n\
        addic   %0,%0,1\n"
        PPC405_ERR77(0,%1)
@@ -150,7 +150,7 @@ static __inline__ int atomic_dec_return(atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%1         # atomic_dec_return\n\
        addic   %0,%0,-1\n"
        PPC405_ERR77(0,%1)
@@ -176,19 +176,19 @@ 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);                                                                   \
-          for (;;) {                                                                                     \
-                          if (unlikely(c == (u)))                                               \
-                                          break;                                                                 \
-                          old = atomic_cmpxchg((v), c, c + (a));                 \
-                          if (likely(old == c))                                                   \
-                                          break;                                                                 \
-                          c = old;                                                                             \
-          }                                                                                                       \
-          c != (u);                                                                                       \
+#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 atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
@@ -204,7 +204,7 @@ static __inline__ int atomic_dec_if_positive(atomic_t *v)
        int t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%1         # atomic_dec_if_positive\n\
        addic.  %0,%0,-1\n\
        blt-    2f\n"
@@ -253,7 +253,7 @@ static __inline__ long atomic64_add_return(long a, atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%2         # atomic64_add_return\n\
        add     %0,%1,%0\n\
        stdcx.  %0,0,%2 \n\
@@ -287,7 +287,7 @@ static __inline__ long atomic64_sub_return(long a, atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%2         # atomic64_sub_return\n\
        subf    %0,%1,%0\n\
        stdcx.  %0,0,%2 \n\
@@ -319,7 +319,7 @@ static __inline__ long atomic64_inc_return(atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%1         # atomic64_inc_return\n\
        addic   %0,%0,1\n\
        stdcx.  %0,0,%1 \n\
@@ -361,7 +361,7 @@ static __inline__ long atomic64_dec_return(atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%1         # atomic64_dec_return\n\
        addic   %0,%0,-1\n\
        stdcx.  %0,0,%1\n\
@@ -386,7 +386,7 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
        long t;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%1         # atomic64_dec_if_positive\n\
        addic.  %0,%0,-1\n\
        blt-    2f\n\
index 1996eaa8aeae9abe0644277c87e384809d378957..bf6941a810b85badf664f56343a59b50cbdec289 100644 (file)
@@ -112,7 +112,7 @@ static __inline__ int test_and_set_bit(unsigned long nr,
        unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:"   PPC_LLARX "%0,0,%3              # test_and_set_bit\n"
        "or     %1,%0,%2 \n"
        PPC405_ERR77(0,%3)
@@ -134,7 +134,7 @@ static __inline__ int test_and_clear_bit(unsigned long nr,
        unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:"   PPC_LLARX "%0,0,%3              # test_and_clear_bit\n"
        "andc   %1,%0,%2 \n"
        PPC405_ERR77(0,%3)
@@ -156,7 +156,7 @@ static __inline__ int test_and_change_bit(unsigned long nr,
        unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:"   PPC_LLARX "%0,0,%3              # test_and_change_bit\n"
        "xor    %1,%0,%2 \n"
        PPC405_ERR77(0,%3)
index ef6ead34a773c358aa45dc6e802df198ff4d4898..64210549f56b2b52cca83cddd84c489daec3c4e4 100644 (file)
@@ -19,6 +19,7 @@
 #define PPC_FEATURE_POWER5             0x00040000
 #define PPC_FEATURE_POWER5_PLUS                0x00020000
 #define PPC_FEATURE_CELL               0x00010000
+#define PPC_FEATURE_BOOKE              0x00008000
 
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
@@ -31,11 +32,11 @@ struct cpu_spec;
 typedef        void (*cpu_setup_t)(unsigned long offset, struct cpu_spec* spec);
 
 enum powerpc_oprofile_type {
-       INVALID = 0,
-       RS64 = 1,
-       POWER4 = 2,
-       G4 = 3,
-       BOOKE = 4,
+       PPC_OPROFILE_INVALID = 0,
+       PPC_OPROFILE_RS64 = 1,
+       PPC_OPROFILE_POWER4 = 2,
+       PPC_OPROFILE_G4 = 3,
+       PPC_OPROFILE_BOOKE = 4,
 };
 
 struct cpu_spec {
@@ -64,6 +65,9 @@ struct cpu_spec {
 
        /* Processor specific oprofile operations */
        enum powerpc_oprofile_type oprofile_type;
+
+       /* Name of processor class, for the ELF AT_PLATFORM entry */
+       char            *platform;
 };
 
 extern struct cpu_spec         *cur_cpu_spec;
index 45f2af6f89c47a209ac17d3207901b6260c404ee..94d228f9c6ac0a799e2b431f6464b5e124c1258e 100644 (file)
@@ -221,20 +221,18 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
    instruction set this cpu supports.  This could be done in userspace,
    but it's not easy, and we've already done it here.  */
 # define ELF_HWCAP     (cur_cpu_spec->cpu_user_features)
-#ifdef __powerpc64__
-# define ELF_PLAT_INIT(_r, load_addr)  do {    \
-       _r->gpr[2] = load_addr;                 \
-} while (0)
-#endif /* __powerpc64__ */
 
 /* 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.
+   intent than poking at uname or /proc/cpuinfo.  */
 
-   For the moment, we have only optimizations for the Intel generations,
-   but that could change... */
+#define ELF_PLATFORM   (cur_cpu_spec->platform)
 
-#define ELF_PLATFORM   (NULL)
+#ifdef __powerpc64__
+# define ELF_PLAT_INIT(_r, load_addr)  do {    \
+       _r->gpr[2] = load_addr;                 \
+} while (0)
+#endif /* __powerpc64__ */
 
 #ifdef __KERNEL__
 
index f0319d50b129e034cebbbd2da463d0e8a1242723..39e85f320a76e74d010e8ce76bcec130b16245a7 100644 (file)
@@ -11,7 +11,7 @@
 
 #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
   __asm__ __volatile ( \
-       SYNC_ON_SMP \
+       LWSYNC_ON_SMP \
 "1:    lwarx   %0,0,%2\n" \
        insn \
        PPC405_ERR77(0, %2) \
index da7af5a720e098adf14ad1ccf9b0817e9d429fde..38ca9ad6110d6640b37a1b0e06bd8ed50599abbc 100644 (file)
@@ -6,7 +6,10 @@
 
 #define H_Success      0
 #define H_Busy         1       /* Hardware busy -- retry later */
+#define H_Closed       2       /* Resource closed */
 #define H_Constrained  4       /* Resource request constrained to max allowed */
+#define H_InProgress   14      /* Kind of like busy */
+#define H_Continue     18      /* Returned from H_Join on success */
 #define H_LongBusyStartRange   9900  /* Start of long busy range */
 #define H_LongBusyOrder1msec   9900  /* Long busy, hint that 1msec is a good time to retry */
 #define H_LongBusyOrder10msec  9901  /* Long busy, hint that 10msec is a good time to retry */
 #define H_REGISTER_VTERM       0x154
 #define H_FREE_VTERM           0x158
 #define H_POLL_PENDING         0x1D8
+#define H_JOIN                 0x298
+#define H_ENABLE_CRQ           0x2B0
 
 #ifndef __ASSEMBLY__
 
index fffdf690b8404548b47d3747a17b521682158038..640a6459f2f4604017c3fb14a452ecdbf0ba62ac 100644 (file)
 #define KEXEC_ARCH KEXEC_ARCH_PPC
 #endif
 
-#define HAVE_ARCH_COPY_OLDMEM_PAGE
-
-#ifndef __ASSEMBLY__
-
 #ifdef CONFIG_KEXEC
 
+#ifdef __powerpc64__
+/*
+ * This function is responsible for capturing register states if coming
+ * via panic or invoking dump using sysrq-trigger.
+ */
+static inline void crash_setup_regs(struct pt_regs *newregs,
+                                       struct pt_regs *oldregs)
+{
+       if (oldregs)
+               memcpy(newregs, oldregs, sizeof(*newregs));
+       else {
+               /* FIXME Merge this with xmon_save_regs ?? */
+               unsigned long tmp1, tmp2;
+               __asm__ __volatile__ (
+                       "std    0,0(%2)\n"
+                       "std    1,8(%2)\n"
+                       "std    2,16(%2)\n"
+                       "std    3,24(%2)\n"
+                       "std    4,32(%2)\n"
+                       "std    5,40(%2)\n"
+                       "std    6,48(%2)\n"
+                       "std    7,56(%2)\n"
+                       "std    8,64(%2)\n"
+                       "std    9,72(%2)\n"
+                       "std    10,80(%2)\n"
+                       "std    11,88(%2)\n"
+                       "std    12,96(%2)\n"
+                       "std    13,104(%2)\n"
+                       "std    14,112(%2)\n"
+                       "std    15,120(%2)\n"
+                       "std    16,128(%2)\n"
+                       "std    17,136(%2)\n"
+                       "std    18,144(%2)\n"
+                       "std    19,152(%2)\n"
+                       "std    20,160(%2)\n"
+                       "std    21,168(%2)\n"
+                       "std    22,176(%2)\n"
+                       "std    23,184(%2)\n"
+                       "std    24,192(%2)\n"
+                       "std    25,200(%2)\n"
+                       "std    26,208(%2)\n"
+                       "std    27,216(%2)\n"
+                       "std    28,224(%2)\n"
+                       "std    29,232(%2)\n"
+                       "std    30,240(%2)\n"
+                       "std    31,248(%2)\n"
+                       "mfmsr  %0\n"
+                       "std    %0, 264(%2)\n"
+                       "mfctr  %0\n"
+                       "std    %0, 280(%2)\n"
+                       "mflr   %0\n"
+                       "std    %0, 288(%2)\n"
+                       "bl     1f\n"
+               "1:     mflr   %1\n"
+                       "std    %1, 256(%2)\n"
+                       "mtlr   %0\n"
+                       "mfxer  %0\n"
+                       "std    %0, 296(%2)\n"
+                       : "=&r" (tmp1), "=&r" (tmp2)
+                       : "b" (newregs));
+       }
+}
+#else
+/*
+ * Provide a dummy definition to avoid build failures. Will remain
+ * empty till crash dump support is enabled.
+ */
+static inline void crash_setup_regs(struct pt_regs *newregs,
+                                       struct pt_regs *oldregs) { }
+#endif /* !__powerpc64 __ */
+
+#ifndef __ASSEMBLY__
 #define MAX_NOTE_BYTES 1024
 
 #ifdef __powerpc64__
@@ -53,14 +121,7 @@ extern void default_machine_kexec(struct kimage *image);
 extern int default_machine_kexec_prepare(struct kimage *image);
 extern void default_machine_crash_shutdown(struct pt_regs *regs);
 
-#endif /* !CONFIG_KEXEC */
-
-/*
- * Provide a dummy definition to avoid build failures. Will remain
- * empty till crash dump support is enabled.
- */
-static inline void crash_setup_regs(struct pt_regs *newregs,
-                                       struct pt_regs *oldregs) { }
 #endif /* ! __ASSEMBLY__ */
+#endif /* CONFIG_KEXEC */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_KEXEC_H */
index ff82ea7c48292bcfcf194f06d1a7c88e5459b370..cd9f11f1ef14b7ac8f44d2868f5a35b6c7548eca 100644 (file)
@@ -29,7 +29,9 @@
 //----------------------------------------------------------------------------
 #include <asm/types.h>
 
-struct lppaca {
+/* The Hypervisor barfs if the lppaca crosses a page boundary.  A 1k
+ * alignment is sufficient to prevent this */
+struct __attribute__((__aligned__(0x400))) lppaca {
 //=============================================================================
 // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
 // NOTE: The xDynXyz fields are fields that will be dynamically changed by
@@ -129,5 +131,7 @@ struct lppaca {
        u8      pmc_save_area[256];     // PMC interrupt Area           x00-xFF
 };
 
+extern struct lppaca lppaca[];
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_LPPACA_H */
index a64b4d425dab3c4b6041422464da182ed3713009..c9add8f1ad94b1e30d6430de06ad7d1fba5a63b0 100644 (file)
@@ -23,6 +23,7 @@
 
 register struct paca_struct *local_paca asm("r13");
 #define get_paca()     local_paca
+#define get_lppaca()   (get_paca()->lppaca_ptr)
 
 struct task_struct;
 
@@ -95,19 +96,6 @@ struct paca_struct {
        u64 saved_r1;                   /* r1 save for RTAS calls */
        u64 saved_msr;                  /* MSR saved here by enter_rtas */
        u8 proc_enabled;                /* irq soft-enable flag */
-
-       /*
-        * iSeries structure which the hypervisor knows about -
-        * this structure should not cross a page boundary.
-        * The vpa_init/register_vpa call is now known to fail if the
-        * lppaca structure crosses a page boundary.
-        * The lppaca is also used on POWER5 pSeries boxes.
-        * The lppaca is 640 bytes long, and cannot readily change
-        * since the hypervisor knows its layout, so a 1kB
-        * alignment will suffice to ensure that it doesn't
-        * cross a page boundary.
-        */
-       struct lppaca lppaca __attribute__((__aligned__(0x400)));
 };
 
 extern struct paca_struct paca[];
index 0dc798d46ea462bc33759f1637f708928c61bbc7..ab8688d39024763ca01cd626035330015a06fab8 100644 (file)
@@ -156,52 +156,56 @@ n:
 #endif
 
 /* 
- * LOADADDR( rn, name )
- *   loads the address of 'name' into 'rn'
+ * LOAD_REG_IMMEDIATE(rn, expr)
+ *   Loads the value of the constant expression 'expr' into register 'rn'
+ *   using immediate instructions only.  Use this when it's important not
+ *   to reference other data (i.e. on ppc64 when the TOC pointer is not
+ *   valid).
  *
- * LOADBASE( rn, name )
- *   loads the address (possibly without the low 16 bits) of 'name' into 'rn'
- *   suitable for base+disp addressing
+ * LOAD_REG_ADDR(rn, name)
+ *   Loads the address of label 'name' into register 'rn'.  Use this when
+ *   you don't particularly need immediate instructions only, but you need
+ *   the whole address in one register (e.g. it's a structure address and
+ *   you want to access various offsets within it).  On ppc32 this is
+ *   identical to LOAD_REG_IMMEDIATE.
+ *
+ * LOAD_REG_ADDRBASE(rn, name)
+ * ADDROFF(name)
+ *   LOAD_REG_ADDRBASE loads part of the address of label 'name' into
+ *   register 'rn'.  ADDROFF(name) returns the remainder of the address as
+ *   a constant expression.  ADDROFF(name) is a signed expression < 16 bits
+ *   in size, so is suitable for use directly as an offset in load and store
+ *   instructions.  Use this when loading/storing a single word or less as:
+ *      LOAD_REG_ADDRBASE(rX, name)
+ *      ld     rY,ADDROFF(name)(rX)
  */
 #ifdef __powerpc64__
-#define LOADADDR(rn,name) \
-       lis     rn,name##@highest;      \
-       ori     rn,rn,name##@higher;    \
-       rldicr  rn,rn,32,31;            \
-       oris    rn,rn,name##@h;         \
-       ori     rn,rn,name##@l
-
-#define LOADBASE(rn,name)              \
-       ld      rn,name@got(r2)
-
-#define OFF(name)      0
-
-#define SET_REG_TO_CONST(reg, value)                   \
-       lis     reg,(((value)>>48)&0xFFFF);             \
-       ori     reg,reg,(((value)>>32)&0xFFFF);         \
-       rldicr  reg,reg,32,31;                          \
-       oris    reg,reg,(((value)>>16)&0xFFFF);         \
-       ori     reg,reg,((value)&0xFFFF);
-
-#define SET_REG_TO_LABEL(reg, label)                   \
-       lis     reg,(label)@highest;                    \
-       ori     reg,reg,(label)@higher;                 \
-       rldicr  reg,reg,32,31;                          \
-       oris    reg,reg,(label)@h;                      \
-       ori     reg,reg,(label)@l;
+#define LOAD_REG_IMMEDIATE(reg,expr)           \
+       lis     (reg),(expr)@highest;           \
+       ori     (reg),(reg),(expr)@higher;      \
+       rldicr  (reg),(reg),32,31;              \
+       oris    (reg),(reg),(expr)@h;           \
+       ori     (reg),(reg),(expr)@l;
+
+#define LOAD_REG_ADDR(reg,name)                        \
+       ld      (reg),name@got(r2)
+
+#define LOAD_REG_ADDRBASE(reg,name)    LOAD_REG_ADDR(reg,name)
+#define ADDROFF(name)                  0
 
 /* offsets for stack frame layout */
 #define LRSAVE 16
 
 #else /* 32-bit */
-#define LOADADDR(rn,name) \
-       lis     rn,name@ha;     \
-       addi    rn,rn,name@l
 
-#define LOADBASE(rn,name)      \
-       lis     rn,name@ha
+#define LOAD_REG_IMMEDIATE(reg,expr)           \
+       lis     (reg),(expr)@ha;                \
+       addi    (reg),(reg),(expr)@l;
+
+#define LOAD_REG_ADDR(reg,name)                LOAD_REG_IMMEDIATE(reg, name)
 
-#define OFF(name)      name@l
+#define LOAD_REG_ADDRBASE(reg, name)   lis     (reg),name@ha
+#define ADDROFF(name)                  name@l
 
 /* offsets for stack frame layout */
 #define LRSAVE 4
index 329e9bf62260cd69c074430224b547855c70bd12..5b2bd4eefb01870e4a31647232331a1d10bbd962 100644 (file)
@@ -87,6 +87,7 @@ struct device_node {
        char    *full_name;
 
        struct  property *properties;
+       struct  property *deadprops; /* removed properties */
        struct  device_node *parent;
        struct  device_node *child;
        struct  device_node *sibling;
@@ -135,6 +136,9 @@ extern struct device_node *of_find_all_nodes(struct device_node *prev);
 extern struct device_node *of_get_parent(const struct device_node *node);
 extern struct device_node *of_get_next_child(const struct device_node *node,
                                             struct device_node *prev);
+extern struct property *of_find_property(struct device_node *np,
+                                        const char *name,
+                                        int *lenp);
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
 
@@ -164,6 +168,10 @@ extern int prom_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);
+extern int prom_remove_property(struct device_node *np, struct property *prop);
+extern int prom_update_property(struct device_node *np,
+                               struct property *newprop,
+                               struct property *oldprop);
 
 #ifdef CONFIG_PPC32
 /*
index 754900901cd8fbeb05673bdb086a6f41a1b92655..895cb6d3a42a9cd1436670338f7a9fe3c0d53ae6 100644 (file)
@@ -46,7 +46,7 @@ static __inline__ unsigned long __spin_trylock(raw_spinlock_t *lock)
 
        token = LOCK_TOKEN;
        __asm__ __volatile__(
-"1:    lwarx           %0,0,%2         # __spin_trylock\n\
+"1:    lwarx           %0,0,%2\n\
        cmpwi           0,%0,0\n\
        bne-            2f\n\
        stwcx.          %1,0,%2\n\
@@ -80,7 +80,7 @@ static int __inline__ __raw_spin_trylock(raw_spinlock_t *lock)
 
 #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
 /* We only yield to the hypervisor if we are in shared processor mode */
-#define SHARED_PROCESSOR (get_paca()->lppaca.shared_proc)
+#define SHARED_PROCESSOR (get_lppaca()->shared_proc)
 extern void __spin_yield(raw_spinlock_t *lock);
 extern void __rw_yield(raw_rwlock_t *lock);
 #else /* SPLPAR || ISERIES */
@@ -124,8 +124,8 @@ static void __inline__ __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long
 
 static __inline__ void __raw_spin_unlock(raw_spinlock_t *lock)
 {
-       __asm__ __volatile__(SYNC_ON_SMP"       # __raw_spin_unlock"
-                            : : :"memory");
+       __asm__ __volatile__("# __raw_spin_unlock\n\t"
+                               LWSYNC_ON_SMP: : :"memory");
        lock->slock = 0;
 }
 
@@ -167,7 +167,7 @@ static long __inline__ __read_trylock(raw_rwlock_t *rw)
        long tmp;
 
        __asm__ __volatile__(
-"1:    lwarx           %0,0,%1         # read_trylock\n"
+"1:    lwarx           %0,0,%1\n"
        __DO_SIGN_EXTEND
 "      addic.          %0,%0,1\n\
        ble-            2f\n"
@@ -192,7 +192,7 @@ static __inline__ long __write_trylock(raw_rwlock_t *rw)
 
        token = WRLOCK_TOKEN;
        __asm__ __volatile__(
-"1:    lwarx           %0,0,%2 # write_trylock\n\
+"1:    lwarx           %0,0,%2\n\
        cmpwi           0,%0,0\n\
        bne-            2f\n"
        PPC405_ERR77(0,%1)
@@ -249,8 +249,9 @@ static void __inline__ __raw_read_unlock(raw_rwlock_t *rw)
        long tmp;
 
        __asm__ __volatile__(
-       "eieio                          # read_unlock\n\
-1:     lwarx           %0,0,%1\n\
+       "# read_unlock\n\t"
+       LWSYNC_ON_SMP
+"1:    lwarx           %0,0,%1\n\
        addic           %0,%0,-1\n"
        PPC405_ERR77(0,%1)
 "      stwcx.          %0,0,%1\n\
@@ -262,8 +263,8 @@ static void __inline__ __raw_read_unlock(raw_rwlock_t *rw)
 
 static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
 {
-       __asm__ __volatile__(SYNC_ON_SMP"       # write_unlock"
-                            : : :"memory");
+       __asm__ __volatile__("# write_unlock\n\t"
+                               LWSYNC_ON_SMP: : :"memory");
        rw->lock = 0;
 }
 
index 794870ab8fd3edfb802fa22cb2d513c94794de8b..c90d9d9aae720f6638e6896e0437442a1c65bb47 100644 (file)
@@ -2,6 +2,8 @@
 #define _ASM_POWERPC_SYNCH_H 
 #ifdef __KERNEL__
 
+#include <linux/stringify.h>
+
 #ifdef __powerpc64__
 #define __SUBARCH_HAS_LWSYNC
 #endif
 #    define LWSYNC     sync
 #endif
 
-
-/*
- * Arguably the bitops and *xchg operations don't imply any memory barrier
- * or SMP ordering, but in fact a lot of drivers expect them to imply
- * both, since they do on x86 cpus.
- */
 #ifdef CONFIG_SMP
-#define EIEIO_ON_SMP   "eieio\n"
 #define ISYNC_ON_SMP   "\n\tisync"
-#define SYNC_ON_SMP    __stringify(LWSYNC) "\n"
+#define LWSYNC_ON_SMP  __stringify(LWSYNC) "\n"
 #else
-#define EIEIO_ON_SMP
 #define ISYNC_ON_SMP
-#define SYNC_ON_SMP
+#define LWSYNC_ON_SMP
 #endif
 
 static inline void eieio(void)
@@ -38,14 +32,5 @@ static inline void isync(void)
        __asm__ __volatile__ ("isync" : : : "memory");
 }
 
-#ifdef CONFIG_SMP
-#define eieio_on_smp() eieio()
-#define isync_on_smp() isync()
-#else
-#define eieio_on_smp() __asm__ __volatile__("": : :"memory")
-#define isync_on_smp() __asm__ __volatile__("": : :"memory")
-#endif
-
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SYNCH_H */
-
index 9b822afa7d0e1b72d47c2368b16f286074f6bb00..d9bf53653b10de8175fba20f16be1b9840a5f61a 100644 (file)
@@ -212,7 +212,7 @@ __xchg_u32(volatile void *p, unsigned long val)
        unsigned long prev;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%2 \n"
        PPC405_ERR77(0,%2)
 "      stwcx.  %3,0,%2 \n\
@@ -232,7 +232,7 @@ __xchg_u64(volatile void *p, unsigned long val)
        unsigned long prev;
 
        __asm__ __volatile__(
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%2 \n"
        PPC405_ERR77(0,%2)
 "      stdcx.  %3,0,%2 \n\
@@ -287,7 +287,7 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
        unsigned int prev;
 
        __asm__ __volatile__ (
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    lwarx   %0,0,%2         # __cmpxchg_u32\n\
        cmpw    0,%0,%3\n\
        bne-    2f\n"
@@ -311,7 +311,7 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
        unsigned long prev;
 
        __asm__ __volatile__ (
-       EIEIO_ON_SMP
+       LWSYNC_ON_SMP
 "1:    ldarx   %0,0,%2         # __cmpxchg_u64\n\
        cmpd    0,%0,%3\n\
        bne-    2f\n\
index d9b86a17271ba95ed500061b3a83e7d98d0104f5..baddc9ab57adc1e561c6805be229449ffc64582b 100644 (file)
@@ -175,11 +175,10 @@ static inline void set_dec(int val)
        set_dec_cpu6(val);
 #else
 #ifdef CONFIG_PPC_ISERIES
-       struct paca_struct *lpaca = get_paca();
        int cur_dec;
 
-       if (lpaca->lppaca.shared_proc) {
-               lpaca->lppaca.virtual_decr = val;
+       if (get_lppaca()->shared_proc) {
+               get_lppaca()->virtual_decr = val;
                cur_dec = get_dec();
                if (cur_dec > val)
                        HvCall_setVirtualDecr();
index eb317a0806e4b713112ced1db1a5592411798ca1..6d431d6fb022df2e180b3af40100719032b8cb50 100644 (file)
@@ -167,6 +167,14 @@ extern int of_address_to_resource(struct device_node *dev, int index,
 extern int of_pci_address_to_resource(struct device_node *dev, int bar,
                                      struct resource *r);
 
+#ifndef CONFIG_PPC_OF
+/*
+ * Fallback definitions for builds where we don't have prom.c included.
+ */
+#define machine_is_compatible(x)               0
+#define of_find_compatible_node(f, t, c)       NULL
+#define get_property(p, n, l)                  NULL
+#endif
 
 #endif /* _PPC_PROM_H */
 #endif /* __KERNEL__ */
index 3ad78f2b9c48720e0aeeff0166dcb74e9beedb6f..6fa20442a48c896bc4836d9295c333a7e7a3a18c 100644 (file)
@@ -2,7 +2,7 @@
  *  include/asm-s390/ccwdev.h
  *
  *    Copyright (C) 2002,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Cornelia Huck <cohuck@de.ibm.com>
+ *    Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *               Carsten Otte  <cotte@de.ibm.com>
  *
  *  Interface for s390 root device
index 803545351dd8d399c41469b32ed82298da36adf7..aeb6e0b13329b512a3d1deb77ee84a349915cecc 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef _ASM_S390_SIGCONTEXT_H
 #define _ASM_S390_SIGCONTEXT_H
 
+#include <linux/compiler.h>
+
 #define __NUM_GPRS 16
 #define __NUM_FPRS 16
 #define __NUM_ACRS 16
index c7c3a9ad593f49682a35f3c7cb0d2a28a952cf17..b2e65e8bf812b9aa14cc92aec006caebb42340d8 100644 (file)
@@ -115,13 +115,14 @@ static inline void sched_cacheflush(void)
 }
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void account_user_vtime(struct task_struct *);
+extern void account_vtime(struct task_struct *);
+extern void account_tick_vtime(struct task_struct *);
 extern void account_system_vtime(struct task_struct *);
 #endif
 
 #define finish_arch_switch(prev) do {                                       \
        set_fs(current->thread.mm_segment);                                  \
-       account_system_vtime(prev);                                          \
+       account_vtime(prev);                                                 \
 } while (0)
 
 #define nop() __asm__ __volatile__ ("nop")
index a582cfcf2231a631564bac9aeda0a4422d8f0ca6..7b286bd21d1dc5e641a72a282cbe92d432ec110e 100644 (file)
@@ -76,7 +76,7 @@ extern void __this_fixmap_does_not_exist(void);
  * directly without translation, we catch the bug with a NULL-deference
  * kernel oops. Illegal ranges of incoming indices are caught too.
  */
-static inline unsigned long fix_to_virt(const unsigned int idx)
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
 {
        /*
         * this branch gets completely eliminated after inlining,
index 2892c4b7a28b01769bd25c88b7a5e9065e7e8a15..bddffcb591b8b26c1068292c459d3d1ae446350b 100644 (file)
@@ -244,7 +244,7 @@ extern unsigned long copy_to_user(void __user *to, const void *from, unsigned le
 extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len); 
 extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len); 
 
-static inline int __copy_from_user(void *dst, const void __user *src, unsigned size) 
+static __always_inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
 { 
        int ret = 0;
        if (!__builtin_constant_p(size))
@@ -273,7 +273,7 @@ static inline int __copy_from_user(void *dst, const void __user *src, unsigned s
        }
 }      
 
-static inline int __copy_to_user(void __user *dst, const void *src, unsigned size) 
+static __always_inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
 { 
        int ret = 0;
        if (!__builtin_constant_p(size))
@@ -305,7 +305,7 @@ static inline int __copy_to_user(void __user *dst, const void *src, unsigned siz
 }      
 
 
-static inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size) 
+static __always_inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 { 
        int ret = 0;
        if (!__builtin_constant_p(size))
index 9a7b374c9fb41a50890b77305131a99ae1a27468..d2bc0d66e65d49ed3df74f2666b3d079a023eeca 100644 (file)
@@ -26,6 +26,6 @@
 
 #define AT_SECURE 23   /* secure mode boolean */
 
-#define AT_VECTOR_SIZE  42 /* Size of auxiliary table.  */
+#define AT_VECTOR_SIZE  44 /* Size of auxiliary table.  */
 
 #endif /* _LINUX_AUXVEC_H */
index 4209082ee934bd788c8f67666360f3f39173cf5f..1698b845761f0127b640135e783b5f7ed0758a62 100644 (file)
@@ -13,3 +13,4 @@
 #define __must_check           __attribute__((warn_unused_result))
 #endif
 
+#define __always_inline                inline __attribute__((always_inline))
index e913e9beaf6909ffbdd604f6759434de8dc213e8..6f5cc6f0e7a66ca521fb1978f27a51099666ec3d 100644 (file)
@@ -3,7 +3,16 @@
 /* These definitions are for GCC v4.x.  */
 #include <linux/compiler-gcc.h>
 
+#ifdef CONFIG_FORCED_INLINING
+# undef inline
+# undef __inline__
+# undef __inline
+# define inline                        inline          __attribute__((always_inline))
+# define __inline__            __inline__      __attribute__((always_inline))
+# define __inline              __inline        __attribute__((always_inline))
+#endif
+
 #define __attribute_used__     __attribute__((__used__))
 #define __must_check           __attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
-
+#define __always_inline                inline __attribute__((always_inline))
index c472f972bd6d5f3f54a6e91352b28be617d0757b..3bc606927116c2b108848fb8f67f80a997dc3b50 100644 (file)
@@ -48,6 +48,9 @@ extern void __cpuset_memory_pressure_bump(void);
 extern struct file_operations proc_cpuset_operations;
 extern char *cpuset_task_status_allowed(struct task_struct *task, char *buffer);
 
+extern void cpuset_lock(void);
+extern void cpuset_unlock(void);
+
 #else /* !CONFIG_CPUSETS */
 
 static inline int cpuset_init_early(void) { return 0; }
@@ -93,6 +96,9 @@ static inline char *cpuset_task_status_allowed(struct task_struct *task,
        return buffer;
 }
 
+static inline void cpuset_lock(void) {}
+static inline void cpuset_unlock(void) {}
+
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
index 0cdee78e5ce16f790142ae146f30d30927fe133a..58df18d9cd3ebe4f218d1d13d119293879a77088 100644 (file)
@@ -49,6 +49,9 @@ struct bus_type {
        int             (*match)(struct device * dev, struct device_driver * drv);
        int             (*uevent)(struct device *dev, char **envp,
                                  int num_envp, char *buffer, int buffer_size);
+       int             (*probe)(struct device * dev);
+       int             (*remove)(struct device * dev);
+       void            (*shutdown)(struct device * dev);
        int             (*suspend)(struct device * dev, pm_message_t state);
        int             (*resume)(struct device * dev);
 };
index a973be2cfe61abb2fb774bc5409225556649c2d1..2cb19e6503aa954003e7ae30703188697bda472b 100644 (file)
@@ -608,15 +608,15 @@ struct fb_ops {
        int (*fb_sync)(struct fb_info *info);
 
        /* perform fb specific ioctl (optional) */
-       int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
-                       unsigned long arg, struct fb_info *info);
+       int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
+                       unsigned long arg);
 
        /* Handle 32bit compat ioctl (optional) */
-       long (*fb_compat_ioctl)(struct file *f, unsigned cmd, unsigned long arg,
-                              struct fb_info *info);
+       int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
+                       unsigned long arg);
 
        /* perform fb specific mmap */
-       int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
+       int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
 
        /* save current hardware state */
        void (*fb_save_state)(struct fb_info *info);
index d1e370d25f7bbe76ed799a4a8788f155950473ff..552cedfa606449a51dc05d1ae548453089134e45 100644 (file)
@@ -1383,6 +1383,12 @@ extern int register_chrdev(unsigned int, const char *,
 extern int unregister_chrdev(unsigned int, const char *);
 extern void unregister_chrdev_region(dev_t, unsigned);
 extern int chrdev_open(struct inode *, struct file *);
+extern int get_chrdev_list(char *);
+extern void *acquire_chrdev_list(void);
+extern int count_chrdev_list(void);
+extern void *get_next_chrdev(void *);
+extern int get_chrdev_info(void *, int *, char **);
+extern void release_chrdev_list(void *);
 
 /* fs/block_dev.c */
 #define BDEVNAME_SIZE  32      /* Largest string for a blockdev identifier */
@@ -1391,6 +1397,11 @@ extern const char *bdevname(struct block_device *bdev, char *buffer);
 extern struct block_device *lookup_bdev(const char *);
 extern struct block_device *open_bdev_excl(const char *, int, void *);
 extern void close_bdev_excl(struct block_device *);
+extern void *acquire_blkdev_list(void);
+extern int count_blkdev_list(void);
+extern void *get_next_blkdev(void *);
+extern int get_blkdev_info(void *, int *, char **);
+extern void release_blkdev_list(void *);
 
 extern void init_special_inode(struct inode *, umode_t, dev_t);
 
index 71d2b8a723b9ad24529f1e8c5896e38cd6419a6b..eab537091f2a1602e55a17b5cdc7a17afb20f99f 100644 (file)
@@ -93,10 +93,6 @@ extern void synchronize_irq(unsigned int irq);
 struct task_struct;
 
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
-static inline void account_user_vtime(struct task_struct *tsk)
-{
-}
-
 static inline void account_system_vtime(struct task_struct *tsk)
 {
 }
index f2e1b5b22898292368273ccd05d0fa09c3045293..110b3cfac021af3be75a1feb2c65fbec359fb72c 100644 (file)
@@ -983,8 +983,13 @@ typedef struct ide_driver_s {
        ide_startstop_t (*abort)(ide_drive_t *, struct request *rq);
        ide_proc_entry_t        *proc;
        struct device_driver    gen_driver;
+       int             (*probe)(ide_drive_t *);
+       void            (*remove)(ide_drive_t *);
+       void            (*shutdown)(ide_drive_t *);
 } ide_driver_t;
 
+#define to_ide_driver(drv) container_of(drv, ide_driver_t, gen_driver)
+
 int generic_ide_ioctl(ide_drive_t *, struct file *, struct block_device *, unsigned, unsigned long);
 
 /*
diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
new file mode 100644 (file)
index 0000000..e7906a7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
+ */
+
+#ifndef _LINUX_IOC3_H
+#define _LINUX_IOC3_H
+
+#include <asm/sn/ioc3.h>
+
+#define IOC3_MAX_SUBMODULES    32
+
+#define IOC3_CLASS_NONE                0
+#define IOC3_CLASS_BASE_IP27   1
+#define IOC3_CLASS_BASE_IP30   2
+#define IOC3_CLASS_MENET_123   3
+#define IOC3_CLASS_MENET_4     4
+#define IOC3_CLASS_CADDUO      5
+#define IOC3_CLASS_SERIAL      6
+
+/* One of these per IOC3 */
+struct ioc3_driver_data {
+       struct list_head list;
+       int id;                         /* IOC3 sequence number */
+       /* PCI mapping */
+       unsigned long pma;              /* physical address */
+       struct __iomem ioc3 *vma;       /* pointer to registers */
+       struct pci_dev *pdev;           /* PCI device */
+       /* IRQ stuff */
+       int dual_irq;                   /* set if separate IRQs are used */
+       int irq_io, irq_eth;            /* IRQ numbers */
+       /* GPIO magic */
+       spinlock_t gpio_lock;
+       unsigned int gpdr_shadow;
+       /* NIC identifiers */
+       char nic_part[32];
+       char nic_serial[16];
+       char nic_mac[6];
+       /* submodule set */
+       int class;
+       void *data[IOC3_MAX_SUBMODULES];        /* for submodule use */
+       int active[IOC3_MAX_SUBMODULES];        /* set if probe succeeds */
+       /* is_ir_lock must be held while
+        * modifying sio_ie values, so
+        * we can be sure that sio_ie is
+        * not changing when we read it
+        * along with sio_ir.
+        */
+       spinlock_t ir_lock;     /* SIO_IE[SC] mod lock */
+};
+
+/* One per submodule */
+struct ioc3_submodule {
+       char *name;             /* descriptive submodule name */
+       struct module *owner;   /* owning kernel module */
+       int ethernet;           /* set for ethernet drivers */
+       int (*probe) (struct ioc3_submodule *, struct ioc3_driver_data *);
+       int (*remove) (struct ioc3_submodule *, struct ioc3_driver_data *);
+       int id;                 /* assigned by IOC3, index for the "data" array */
+       /* IRQ stuff */
+       unsigned int irq_mask;  /* IOC3 IRQ mask, leave clear for Ethernet */
+       int reset_mask;         /* non-zero if you want the ioc3.c module to reset interrupts */
+       int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int, struct pt_regs *);
+       /* private submodule data */
+       void *data;             /* assigned by submodule */
+};
+
+/**********************************
+ * Functions needed by submodules *
+ **********************************/
+
+#define IOC3_W_IES             0
+#define IOC3_W_IEC             1
+
+/* registers a submodule for all existing and future IOC3 chips */
+extern int ioc3_register_submodule(struct ioc3_submodule *);
+/* unregisters a submodule */
+extern void ioc3_unregister_submodule(struct ioc3_submodule *);
+/* enables IRQs indicated by irq_mask for a specified IOC3 chip */
+extern void ioc3_enable(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+/* ackowledges specified IRQs */
+extern void ioc3_ack(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+/* disables IRQs indicated by irq_mask for a specified IOC3 chip */
+extern void ioc3_disable(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
+/* atomically sets GPCR bits */
+extern void ioc3_gpcr_set(struct ioc3_driver_data *, unsigned int);
+/* general ireg writer */
+extern void ioc3_write_ireg(struct ioc3_driver_data *idd, uint32_t value, int reg);
+
+#endif
index e6ee2d95da7a3604d0a7c473ef7396896d21ead9..323924edb26a5f686361bfa6cb188f9b5b4d9641 100644 (file)
@@ -216,6 +216,7 @@ extern void dump_stack(void);
        ((unsigned char *)&addr)[1], \
        ((unsigned char *)&addr)[2], \
        ((unsigned char *)&addr)[3]
+#define NIPQUAD_FMT "%u.%u.%u.%u"
 
 #define NIP6(addr) \
        ntohs((addr).s6_addr16[0]), \
@@ -226,6 +227,7 @@ extern void dump_stack(void);
        ntohs((addr).s6_addr16[5]), \
        ntohs((addr).s6_addr16[6]), \
        ntohs((addr).s6_addr16[7])
+#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
 
 #if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
index c7ac77e873b3fa800e4c4d3a3db0bd43dcaf7192..d6a53ed6ab6c530c490ee43d5fd6a67faa70f48a 100644 (file)
@@ -132,12 +132,8 @@ struct shared_policy {
        spinlock_t lock;
 };
 
-static inline void mpol_shared_policy_init(struct shared_policy *info)
-{
-       info->root = RB_ROOT;
-       spin_lock_init(&info->lock);
-}
-
+void mpol_shared_policy_init(struct shared_policy *info, int policy,
+                               nodemask_t *nodes);
 int mpol_set_shared_policy(struct shared_policy *info,
                                struct vm_area_struct *vma,
                                struct mempolicy *new);
@@ -211,7 +207,8 @@ static inline int mpol_set_shared_policy(struct shared_policy *info,
        return -EINVAL;
 }
 
-static inline void mpol_shared_policy_init(struct shared_policy *info)
+static inline void mpol_shared_policy_init(struct shared_policy *info,
+                                       int policy, nodemask_t *nodes)
 {
 }
 
index c643016499a17860605566a77ea2c622f83f0ffe..85854b867463484cf1cc1c7fe76ae5c4f5ca4201 100644 (file)
@@ -512,7 +512,7 @@ static inline void set_page_links(struct page *page, unsigned long zone,
 extern struct page *mem_map;
 #endif
 
-static inline void *lowmem_page_address(struct page *page)
+static __always_inline void *lowmem_page_address(struct page *page)
 {
        return __va(page_to_pfn(page) << PAGE_SHIFT);
 }
index 7297e4372c0fdfc5452ef6d52c38e243a4419771..e013425685302654e31021c870e4777184ee07a7 100644 (file)
@@ -201,34 +201,6 @@ static inline struct ncp_inode_info *NCP_FINFO(struct inode *inode)
        return container_of(inode, struct ncp_inode_info, vfs_inode);
 }
 
-#ifdef DEBUG_NCP_MALLOC
-
-#include <linux/slab.h>
-
-extern int ncp_malloced;
-extern int ncp_current_malloced;
-
-static inline void *
- ncp_kmalloc(unsigned int size, int priority)
-{
-       ncp_malloced += 1;
-       ncp_current_malloced += 1;
-       return kmalloc(size, priority);
-}
-
-static inline void ncp_kfree_s(void *obj, int size)
-{
-       ncp_current_malloced -= 1;
-       kfree(obj);
-}
-
-#else                          /* DEBUG_NCP_MALLOC */
-
-#define ncp_kmalloc(s,p) kmalloc(s,p)
-#define ncp_kfree_s(o,s) kfree(o)
-
-#endif                         /* DEBUG_NCP_MALLOC */
-
 /* linux/fs/ncpfs/inode.c */
 int ncp_notify_change(struct dentry *, struct iattr *);
 struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *);
index 6d39b518486b94dcda7368a6791919403604ffc7..3ff88c8783083fc620a880ecfbdb44d7840cc8f2 100644 (file)
@@ -154,6 +154,9 @@ struct ip_conntrack_stat
        unsigned int expect_delete;
 };
 
+/* call to create an explicit dependency on nf_conntrack. */
+extern void need_conntrack(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
new file mode 100644 (file)
index 0000000..472f048
--- /dev/null
@@ -0,0 +1,224 @@
+#ifndef _X_TABLES_H
+#define _X_TABLES_H
+
+#define XT_FUNCTION_MAXNAMELEN 30
+#define XT_TABLE_MAXNAMELEN 32
+
+/* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
+ * kernel supports, if >= revision. */
+struct xt_get_revision
+{
+       char name[XT_FUNCTION_MAXNAMELEN-1];
+
+       u_int8_t revision;
+};
+
+/* CONTINUE verdict for targets */
+#define XT_CONTINUE 0xFFFFFFFF
+
+/* For standard target */
+#define XT_RETURN (-NF_REPEAT - 1)
+
+#define XT_ALIGN(s) (((s) + (__alignof__(void *)-1)) & ~(__alignof__(void *)-1))
+
+/* Standard return verdict, or do jump. */
+#define XT_STANDARD_TARGET ""
+/* Error verdict. */
+#define XT_ERROR_TARGET "ERROR"
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use a raw
+ * socket for this. Instead we check rights in the calls. */
+#define XT_BASE_CTL            64      /* base for firewall socket options */
+
+#define XT_SO_SET_REPLACE      (XT_BASE_CTL)
+#define XT_SO_SET_ADD_COUNTERS (XT_BASE_CTL + 1)
+#define XT_SO_SET_MAX          XT_SO_SET_ADD_COUNTERS
+
+#define XT_SO_GET_INFO                 (XT_BASE_CTL)
+#define XT_SO_GET_ENTRIES              (XT_BASE_CTL + 1)
+#define XT_SO_GET_REVISION_MATCH       (XT_BASE_CTL + 2)
+#define XT_SO_GET_REVISION_TARGET      (XT_BASE_CTL + 3)
+#define XT_SO_GET_MAX                  XT_SO_GET_REVISION_TARGET
+
+#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
+#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
+
+struct xt_counters
+{
+       u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
+};
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+struct xt_counters_info
+{
+       /* Which table. */
+       char name[XT_TABLE_MAXNAMELEN];
+
+       unsigned int num_counters;
+
+       /* The counters (actually `number' of these). */
+       struct xt_counters counters[0];
+};
+
+#define XT_INV_PROTO           0x40    /* Invert the sense of PROTO. */
+
+#ifdef __KERNEL__
+
+#include <linux/netdevice.h>
+
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+#include <linux/netfilter_ipv4/listhelp.h>
+
+struct xt_match
+{
+       struct list_head list;
+
+       const char name[XT_FUNCTION_MAXNAMELEN-1];
+
+       u_int8_t revision;
+
+       /* Return true or false: return FALSE and set *hotdrop = 1 to
+           force immediate packet drop. */
+       /* Arguments changed since 2.6.9, as this must now handle
+          non-linear skb, using skb_header_pointer and
+          skb_ip_make_writable. */
+       int (*match)(const struct sk_buff *skb,
+                    const struct net_device *in,
+                    const struct net_device *out,
+                    const void *matchinfo,
+                    int offset,
+                    unsigned int protoff,
+                    int *hotdrop);
+
+       /* Called when user tries to insert an entry of this type. */
+       /* Should return true or false. */
+       int (*checkentry)(const char *tablename,
+                         const void *ip,
+                         void *matchinfo,
+                         unsigned int matchinfosize,
+                         unsigned int hook_mask);
+
+       /* Called when entry of this type deleted. */
+       void (*destroy)(void *matchinfo, unsigned int matchinfosize);
+
+       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+       struct module *me;
+};
+
+/* Registration hooks for targets. */
+struct xt_target
+{
+       struct list_head list;
+
+       const char name[XT_FUNCTION_MAXNAMELEN-1];
+
+       u_int8_t revision;
+
+       /* Returns verdict. Argument order changed since 2.6.9, as this
+          must now handle non-linear skbs, using skb_copy_bits and
+          skb_ip_make_writable. */
+       unsigned int (*target)(struct sk_buff **pskb,
+                              const struct net_device *in,
+                              const struct net_device *out,
+                              unsigned int hooknum,
+                              const void *targinfo,
+                              void *userdata);
+
+       /* Called when user tries to insert an entry of this type:
+           hook_mask is a bitmask of hooks from which it can be
+           called. */
+       /* Should return true or false. */
+       int (*checkentry)(const char *tablename,
+                         const void *entry,
+                         void *targinfo,
+                         unsigned int targinfosize,
+                         unsigned int hook_mask);
+
+       /* Called when entry of this type deleted. */
+       void (*destroy)(void *targinfo, unsigned int targinfosize);
+
+       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+       struct module *me;
+};
+
+/* Furniture shopping... */
+struct xt_table
+{
+       struct list_head list;
+
+       /* A unique name... */
+       char name[XT_TABLE_MAXNAMELEN];
+
+       /* What hooks you will enter on */
+       unsigned int valid_hooks;
+
+       /* Lock for the curtain */
+       rwlock_t lock;
+
+       /* Man behind the curtain... */
+       //struct ip6t_table_info *private;
+       void *private;
+
+       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
+       struct module *me;
+
+       int af;         /* address/protocol family */
+};
+
+#include <linux/netfilter_ipv4.h>
+
+/* The table itself */
+struct xt_table_info
+{
+       /* Size per table */
+       unsigned int size;
+       /* Number of entries: FIXME. --RR */
+       unsigned int number;
+       /* Initial number of entries. Needed for module usage count */
+       unsigned int initial_entries;
+
+       /* Entry points and underflows */
+       unsigned int hook_entry[NF_IP_NUMHOOKS];
+       unsigned int underflow[NF_IP_NUMHOOKS];
+
+       /* ipt_entry tables: one per CPU */
+       char *entries[NR_CPUS];
+};
+
+extern int xt_register_target(int af, struct xt_target *target);
+extern void xt_unregister_target(int af, struct xt_target *target);
+extern int xt_register_match(int af, struct xt_match *target);
+extern void xt_unregister_match(int af, struct xt_match *target);
+
+extern int xt_register_table(struct xt_table *table,
+                            struct xt_table_info *bootstrap,
+                            struct xt_table_info *newinfo);
+extern void *xt_unregister_table(struct xt_table *table);
+
+extern struct xt_table_info *xt_replace_table(struct xt_table *table,
+                                             unsigned int num_counters,
+                                             struct xt_table_info *newinfo,
+                                             int *error);
+
+extern struct xt_match *xt_find_match(int af, const char *name, u8 revision);
+extern struct xt_target *xt_find_target(int af, const char *name, u8 revision);
+extern struct xt_target *xt_request_find_target(int af, const char *name, 
+                                               u8 revision);
+extern int xt_find_revision(int af, const char *name, u8 revision, int target,
+                           int *err);
+
+extern struct xt_table *xt_find_table_lock(int af, const char *name);
+extern void xt_table_unlock(struct xt_table *t);
+
+extern int xt_proto_init(int af);
+extern void xt_proto_fini(int af);
+
+extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
+extern void xt_free_table_info(struct xt_table_info *info);
+
+#endif /* __KERNEL__ */
+
+#endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter/xt_CLASSIFY.h b/include/linux/netfilter/xt_CLASSIFY.h
new file mode 100644 (file)
index 0000000..5811135
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _XT_CLASSIFY_H
+#define _XT_CLASSIFY_H
+
+struct xt_classify_target_info {
+       u_int32_t priority;
+};
+
+#endif /*_XT_CLASSIFY_H */
diff --git a/include/linux/netfilter/xt_CONNMARK.h b/include/linux/netfilter/xt_CONNMARK.h
new file mode 100644 (file)
index 0000000..9f74468
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _XT_CONNMARK_H_target
+#define _XT_CONNMARK_H_target
+
+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.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.
+ */
+
+enum {
+       XT_CONNMARK_SET = 0,
+       XT_CONNMARK_SAVE,
+       XT_CONNMARK_RESTORE
+};
+
+struct xt_connmark_target_info {
+       unsigned long mark;
+       unsigned long mask;
+       u_int8_t mode;
+};
+
+#endif /*_XT_CONNMARK_H_target*/
diff --git a/include/linux/netfilter/xt_MARK.h b/include/linux/netfilter/xt_MARK.h
new file mode 100644 (file)
index 0000000..b021e93
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _XT_MARK_H_target
+#define _XT_MARK_H_target
+
+/* Version 0 */
+struct xt_mark_target_info {
+       unsigned long mark;
+};
+
+/* Version 1 */
+enum {
+       XT_MARK_SET=0,
+       XT_MARK_AND,
+       XT_MARK_OR,
+};
+
+struct xt_mark_target_info_v1 {
+       unsigned long mark;
+       u_int8_t mode;
+};
+
+#endif /*_XT_MARK_H_target */
diff --git a/include/linux/netfilter/xt_NFQUEUE.h b/include/linux/netfilter/xt_NFQUEUE.h
new file mode 100644 (file)
index 0000000..9a9af79
--- /dev/null
@@ -0,0 +1,16 @@
+/* iptables module for using NFQUEUE mechanism
+ *
+ * (C) 2005 Harald Welte <laforge@netfilter.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+*/
+#ifndef _XT_NFQ_TARGET_H
+#define _XT_NFQ_TARGET_H
+
+/* target info */
+struct xt_NFQ_info {
+       u_int16_t queuenum;
+};
+
+#endif /* _XT_NFQ_TARGET_H */
diff --git a/include/linux/netfilter/xt_comment.h b/include/linux/netfilter/xt_comment.h
new file mode 100644 (file)
index 0000000..eacfedc
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _XT_COMMENT_H
+#define _XT_COMMENT_H
+
+#define XT_MAX_COMMENT_LEN 256
+
+struct xt_comment_info {
+       unsigned char comment[XT_MAX_COMMENT_LEN];
+};
+
+#endif /* XT_COMMENT_H */
diff --git a/include/linux/netfilter/xt_connbytes.h b/include/linux/netfilter/xt_connbytes.h
new file mode 100644 (file)
index 0000000..c022c98
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _XT_CONNBYTES_H
+#define _XT_CONNBYTES_H
+
+enum xt_connbytes_what {
+       XT_CONNBYTES_PKTS,
+       XT_CONNBYTES_BYTES,
+       XT_CONNBYTES_AVGPKT,
+};
+
+enum xt_connbytes_direction {
+       XT_CONNBYTES_DIR_ORIGINAL,
+       XT_CONNBYTES_DIR_REPLY,
+       XT_CONNBYTES_DIR_BOTH,
+};
+
+struct xt_connbytes_info
+{
+       struct {
+               aligned_u64 from;       /* count to be matched */
+               aligned_u64 to;         /* count to be matched */
+       } count;
+       u_int8_t what;          /* ipt_connbytes_what */
+       u_int8_t direction;     /* ipt_connbytes_direction */
+};
+#endif
diff --git a/include/linux/netfilter/xt_connmark.h b/include/linux/netfilter/xt_connmark.h
new file mode 100644 (file)
index 0000000..c592f6a
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _XT_CONNMARK_H
+#define _XT_CONNMARK_H
+
+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.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.
+ */
+
+struct xt_connmark_info {
+       unsigned long mark, mask;
+       u_int8_t invert;
+};
+
+#endif /*_XT_CONNMARK_H*/
diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h
new file mode 100644 (file)
index 0000000..34f63cf
--- /dev/null
@@ -0,0 +1,63 @@
+/* Header file for kernel module to match connection tracking information.
+ * GPL (C) 2001  Marc Boucher (marc@mbsi.ca).
+ */
+
+#ifndef _XT_CONNTRACK_H
+#define _XT_CONNTRACK_H
+
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <linux/in.h>
+
+#define XT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define XT_CONNTRACK_STATE_INVALID (1 << 0)
+
+#define XT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
+#define XT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
+#define XT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
+
+/* flags, invflags: */
+#define XT_CONNTRACK_STATE     0x01
+#define XT_CONNTRACK_PROTO     0x02
+#define XT_CONNTRACK_ORIGSRC   0x04
+#define XT_CONNTRACK_ORIGDST   0x08
+#define XT_CONNTRACK_REPLSRC   0x10
+#define XT_CONNTRACK_REPLDST   0x20
+#define XT_CONNTRACK_STATUS    0x40
+#define XT_CONNTRACK_EXPIRES   0x80
+
+/* This is exposed to userspace, so remains frozen in time. */
+struct ip_conntrack_old_tuple
+{
+       struct {
+               __u32 ip;
+               union {
+                       __u16 all;
+               } u;
+       } src;
+
+       struct {
+               __u32 ip;
+               union {
+                       __u16 all;
+               } u;
+
+               /* The protocol. */
+               u16 protonum;
+       } dst;
+};
+
+struct xt_conntrack_info
+{
+       unsigned int statemask, statusmask;
+
+       struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
+       struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
+
+       unsigned long expires_min, expires_max;
+
+       /* Flags word */
+       u_int8_t flags;
+       /* Inverse flags */
+       u_int8_t invflags;
+};
+#endif /*_XT_CONNTRACK_H*/
diff --git a/include/linux/netfilter/xt_dccp.h b/include/linux/netfilter/xt_dccp.h
new file mode 100644 (file)
index 0000000..e0221b9
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _XT_DCCP_H_
+#define _XT_DCCP_H_
+
+#define XT_DCCP_SRC_PORTS              0x01
+#define XT_DCCP_DEST_PORTS             0x02
+#define XT_DCCP_TYPE                   0x04
+#define XT_DCCP_OPTION                 0x08
+
+#define XT_DCCP_VALID_FLAGS            0x0f
+
+struct xt_dccp_info {
+       u_int16_t dpts[2];  /* Min, Max */
+       u_int16_t spts[2];  /* Min, Max */
+
+       u_int16_t flags;
+       u_int16_t invflags;
+
+       u_int16_t typemask;
+       u_int8_t option;
+};
+
+#endif /* _XT_DCCP_H_ */
+
diff --git a/include/linux/netfilter/xt_helper.h b/include/linux/netfilter/xt_helper.h
new file mode 100644 (file)
index 0000000..6b42763
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _XT_HELPER_H
+#define _XT_HELPER_H
+
+struct xt_helper_info {
+       int invert;
+       char name[30];
+};
+#endif /* _XT_HELPER_H */
diff --git a/include/linux/netfilter/xt_length.h b/include/linux/netfilter/xt_length.h
new file mode 100644 (file)
index 0000000..7c2b439
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _XT_LENGTH_H
+#define _XT_LENGTH_H
+
+struct xt_length_info {
+    u_int16_t  min, max;
+    u_int8_t   invert;
+};
+
+#endif /*_XT_LENGTH_H*/
diff --git a/include/linux/netfilter/xt_limit.h b/include/linux/netfilter/xt_limit.h
new file mode 100644 (file)
index 0000000..b3ce653
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _XT_RATE_H
+#define _XT_RATE_H
+
+/* timings are in milliseconds. */
+#define XT_LIMIT_SCALE 10000
+
+/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
+   seconds, or one every 59 hours. */
+struct xt_rateinfo {
+       u_int32_t avg;    /* Average secs between packets * scale */
+       u_int32_t burst;  /* Period multiplier for upper limit. */
+
+       /* Used internally by the kernel */
+       unsigned long prev;
+       u_int32_t credit;
+       u_int32_t credit_cap, cost;
+
+       /* Ugly, ugly fucker. */
+       struct xt_rateinfo *master;
+};
+#endif /*_XT_RATE_H*/
diff --git a/include/linux/netfilter/xt_mac.h b/include/linux/netfilter/xt_mac.h
new file mode 100644 (file)
index 0000000..b892cdc
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _XT_MAC_H
+#define _XT_MAC_H
+
+struct xt_mac_info {
+    unsigned char srcaddr[ETH_ALEN];
+    int invert;
+};
+#endif /*_XT_MAC_H*/
diff --git a/include/linux/netfilter/xt_mark.h b/include/linux/netfilter/xt_mark.h
new file mode 100644 (file)
index 0000000..802dd48
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _XT_MARK_H
+#define _XT_MARK_H
+
+struct xt_mark_info {
+    unsigned long mark, mask;
+    u_int8_t invert;
+};
+
+#endif /*_XT_MARK_H*/
diff --git a/include/linux/netfilter/xt_physdev.h b/include/linux/netfilter/xt_physdev.h
new file mode 100644 (file)
index 0000000..25a7a18
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _XT_PHYSDEV_H
+#define _XT_PHYSDEV_H
+
+#ifdef __KERNEL__
+#include <linux/if.h>
+#endif
+
+#define XT_PHYSDEV_OP_IN               0x01
+#define XT_PHYSDEV_OP_OUT              0x02
+#define XT_PHYSDEV_OP_BRIDGED          0x04
+#define XT_PHYSDEV_OP_ISIN             0x08
+#define XT_PHYSDEV_OP_ISOUT            0x10
+#define XT_PHYSDEV_OP_MASK             (0x20 - 1)
+
+struct xt_physdev_info {
+       char physindev[IFNAMSIZ];
+       char in_mask[IFNAMSIZ];
+       char physoutdev[IFNAMSIZ];
+       char out_mask[IFNAMSIZ];
+       u_int8_t invert;
+       u_int8_t bitmask;
+};
+
+#endif /*_XT_PHYSDEV_H*/
diff --git a/include/linux/netfilter/xt_pkttype.h b/include/linux/netfilter/xt_pkttype.h
new file mode 100644 (file)
index 0000000..f265cf5
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _XT_PKTTYPE_H
+#define _XT_PKTTYPE_H
+
+struct xt_pkttype_info {
+       int     pkttype;
+       int     invert;
+};
+#endif /*_XT_PKTTYPE_H*/
diff --git a/include/linux/netfilter/xt_realm.h b/include/linux/netfilter/xt_realm.h
new file mode 100644 (file)
index 0000000..220e872
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _XT_REALM_H
+#define _XT_REALM_H
+
+struct xt_realm_info {
+       u_int32_t id;
+       u_int32_t mask;
+       u_int8_t invert;
+};
+
+#endif /* _XT_REALM_H */
diff --git a/include/linux/netfilter/xt_sctp.h b/include/linux/netfilter/xt_sctp.h
new file mode 100644 (file)
index 0000000..b157897
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef _XT_SCTP_H_
+#define _XT_SCTP_H_
+
+#define XT_SCTP_SRC_PORTS              0x01
+#define XT_SCTP_DEST_PORTS             0x02
+#define XT_SCTP_CHUNK_TYPES            0x04
+
+#define XT_SCTP_VALID_FLAGS            0x07
+
+#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
+
+
+struct xt_sctp_flag_info {
+       u_int8_t chunktype;
+       u_int8_t flag;
+       u_int8_t flag_mask;
+};
+
+#define XT_NUM_SCTP_FLAGS      4
+
+struct xt_sctp_info {
+       u_int16_t dpts[2];  /* Min, Max */
+       u_int16_t spts[2];  /* Min, Max */
+
+       u_int32_t chunkmap[256 / sizeof (u_int32_t)];  /* Bit mask of chunks to be matched according to RFC 2960 */
+
+#define SCTP_CHUNK_MATCH_ANY   0x01  /* Match if any of the chunk types are present */
+#define SCTP_CHUNK_MATCH_ALL   0x02  /* Match if all of the chunk types are present */
+#define SCTP_CHUNK_MATCH_ONLY  0x04  /* Match if these are the only chunk types present */
+
+       u_int32_t chunk_match_type;
+       struct xt_sctp_flag_info flag_info[XT_NUM_SCTP_FLAGS];
+       int flag_count;
+
+       u_int32_t flags;
+       u_int32_t invflags;
+};
+
+#define bytes(type) (sizeof(type) * 8)
+
+#define SCTP_CHUNKMAP_SET(chunkmap, type)              \
+       do {                                            \
+               chunkmap[type / bytes(u_int32_t)] |=    \
+                       1 << (type % bytes(u_int32_t)); \
+       } while (0)
+
+#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)                    \
+       do {                                                    \
+               chunkmap[type / bytes(u_int32_t)] &=            \
+                       ~(1 << (type % bytes(u_int32_t)));      \
+       } while (0)
+
+#define SCTP_CHUNKMAP_IS_SET(chunkmap, type)                   \
+({                                                             \
+       (chunkmap[type / bytes (u_int32_t)] &                   \
+               (1 << (type % bytes (u_int32_t)))) ? 1: 0;      \
+})
+
+#define SCTP_CHUNKMAP_RESET(chunkmap)                          \
+       do {                                                    \
+               int i;                                          \
+               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
+                       chunkmap[i] = 0;                        \
+       } while (0)
+
+#define SCTP_CHUNKMAP_SET_ALL(chunkmap)                        \
+       do {                                                    \
+               int i;                                          \
+               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
+                       chunkmap[i] = ~0;                       \
+       } while (0)
+
+#define SCTP_CHUNKMAP_COPY(destmap, srcmap)                    \
+       do {                                                    \
+               int i;                                          \
+               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
+                       destmap[i] = srcmap[i];                 \
+       } while (0)
+
+#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap)               \
+({                                                     \
+       int i;                                          \
+       int flag = 1;                                   \
+       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
+               if (chunkmap[i]) {                      \
+                       flag = 0;                       \
+                       break;                          \
+               }                                       \
+       }                                               \
+        flag;                                          \
+})
+
+#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)             \
+({                                                     \
+       int i;                                          \
+       int flag = 1;                                   \
+       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
+               if (chunkmap[i] != ~0) {                \
+                       flag = 0;                       \
+                               break;                  \
+               }                                       \
+       }                                               \
+        flag;                                          \
+})
+
+#endif /* _XT_SCTP_H_ */
+
diff --git a/include/linux/netfilter/xt_state.h b/include/linux/netfilter/xt_state.h
new file mode 100644 (file)
index 0000000..c06f32e
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _XT_STATE_H
+#define _XT_STATE_H
+
+#define XT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
+#define XT_STATE_INVALID (1 << 0)
+
+#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
+
+struct xt_state_info
+{
+       unsigned int statemask;
+};
+#endif /*_XT_STATE_H*/
diff --git a/include/linux/netfilter/xt_string.h b/include/linux/netfilter/xt_string.h
new file mode 100644 (file)
index 0000000..3b3419f
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _XT_STRING_H
+#define _XT_STRING_H
+
+#define XT_STRING_MAX_PATTERN_SIZE 128
+#define XT_STRING_MAX_ALGO_NAME_SIZE 16
+
+struct xt_string_info
+{
+       u_int16_t from_offset;
+       u_int16_t to_offset;
+       char      algo[XT_STRING_MAX_ALGO_NAME_SIZE];
+       char      pattern[XT_STRING_MAX_PATTERN_SIZE];
+       u_int8_t  patlen;
+       u_int8_t  invert;
+       struct ts_config __attribute__((aligned(8))) *config;
+};
+
+#endif /*_XT_STRING_H*/
diff --git a/include/linux/netfilter/xt_tcpmss.h b/include/linux/netfilter/xt_tcpmss.h
new file mode 100644 (file)
index 0000000..e03274c
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _XT_TCPMSS_MATCH_H
+#define _XT_TCPMSS_MATCH_H
+
+struct xt_tcpmss_match_info {
+    u_int16_t mss_min, mss_max;
+    u_int8_t invert;
+};
+
+#endif /*_XT_TCPMSS_MATCH_H*/
diff --git a/include/linux/netfilter/xt_tcpudp.h b/include/linux/netfilter/xt_tcpudp.h
new file mode 100644 (file)
index 0000000..78bc65f
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _XT_TCPUDP_H
+#define _XT_TCPUDP_H
+
+/* TCP matching stuff */
+struct xt_tcp
+{
+       u_int16_t spts[2];                      /* Source port range. */
+       u_int16_t dpts[2];                      /* Destination port range. */
+       u_int8_t option;                        /* TCP Option iff non-zero*/
+       u_int8_t flg_mask;                      /* TCP flags mask byte */
+       u_int8_t flg_cmp;                       /* TCP flags compare byte */
+       u_int8_t invflags;                      /* Inverse flags */
+};
+
+/* Values for "inv" field in struct ipt_tcp. */
+#define XT_TCP_INV_SRCPT       0x01    /* Invert the sense of source ports. */
+#define XT_TCP_INV_DSTPT       0x02    /* Invert the sense of dest ports. */
+#define XT_TCP_INV_FLAGS       0x04    /* Invert the sense of TCP flags. */
+#define XT_TCP_INV_OPTION      0x08    /* Invert the sense of option test. */
+#define XT_TCP_INV_MASK                0x0F    /* All possible flags. */
+
+/* UDP matching stuff */
+struct xt_udp
+{
+       u_int16_t spts[2];                      /* Source port range. */
+       u_int16_t dpts[2];                      /* Destination port range. */
+       u_int8_t invflags;                      /* Inverse flags */
+};
+
+/* Values for "invflags" field in struct ipt_udp. */
+#define XT_UDP_INV_SRCPT       0x01    /* Invert the sense of source ports. */
+#define XT_UDP_INV_DSTPT       0x02    /* Invert the sense of dest ports. */
+#define XT_UDP_INV_MASK        0x03    /* All possible flags. */
+
+
+#endif
index e98a870a20be368e099a688dddd8e92f7dbec4f7..fd21796e513141af6f77239a9ddd9a1df06f956e 100644 (file)
 #include <linux/compiler.h>
 #include <linux/netfilter_arp.h>
 
-#define ARPT_FUNCTION_MAXNAMELEN 30
-#define ARPT_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define arpt_target xt_target
+#define arpt_table xt_table
 
 #define ARPT_DEV_ADDR_LEN_MAX 16
 
@@ -91,11 +95,6 @@ struct arpt_standard_target
        int verdict;
 };
 
-struct arpt_counters
-{
-       u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
-};
-
 /* Values for "flag" field in struct arpt_ip (general arp structure).
  * No flags defined yet.
  */
@@ -130,7 +129,7 @@ struct arpt_entry
        unsigned int comefrom;
 
        /* Packet and byte counters. */
-       struct arpt_counters counters;
+       struct xt_counters counters;
 
        /* The matches (if any), then the target. */
        unsigned char elems[0];
@@ -141,23 +140,24 @@ struct arpt_entry
  * Unlike BSD Linux inherits IP options so you don't have to use a raw
  * socket for this. Instead we check rights in the calls.
  */
-#define ARPT_BASE_CTL          96      /* base for firewall socket options */
+#define ARPT_CTL_OFFSET                32
+#define ARPT_BASE_CTL          (XT_BASE_CTL+ARPT_CTL_OFFSET)
 
-#define ARPT_SO_SET_REPLACE            (ARPT_BASE_CTL)
-#define ARPT_SO_SET_ADD_COUNTERS       (ARPT_BASE_CTL + 1)
-#define ARPT_SO_SET_MAX                        ARPT_SO_SET_ADD_COUNTERS
+#define ARPT_SO_SET_REPLACE            (XT_SO_SET_REPLACE+ARPT_CTL_OFFSET)
+#define ARPT_SO_SET_ADD_COUNTERS       (XT_SO_SET_ADD_COUNTERS+ARPT_CTL_OFFSET)
+#define ARPT_SO_SET_MAX                        (XT_SO_SET_MAX+ARPT_CTL_OFFSET)
 
-#define ARPT_SO_GET_INFO               (ARPT_BASE_CTL)
-#define ARPT_SO_GET_ENTRIES            (ARPT_BASE_CTL + 1)
-/* #define ARPT_SO_GET_REVISION_MATCH  (ARPT_BASE_CTL + 2)*/
-#define ARPT_SO_GET_REVISION_TARGET    (ARPT_BASE_CTL + 3)
-#define ARPT_SO_GET_MAX                        ARPT_SO_GET_REVISION_TARGET
+#define ARPT_SO_GET_INFO               (XT_SO_GET_INFO+ARPT_CTL_OFFSET)
+#define ARPT_SO_GET_ENTRIES            (XT_SO_GET_ENTRIES+ARPT_CTL_OFFSET)
+/* #define ARPT_SO_GET_REVISION_MATCH  XT_SO_GET_REVISION_MATCH  */
+#define ARPT_SO_GET_REVISION_TARGET    (XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET)
+#define ARPT_SO_GET_MAX                        (XT_SO_GET_REVISION_TARGET+ARPT_CTL_OFFSET)
 
 /* CONTINUE verdict for targets */
-#define ARPT_CONTINUE 0xFFFFFFFF
+#define ARPT_CONTINUE XT_CONTINUE
 
 /* For standard target */
-#define ARPT_RETURN (-NF_REPEAT - 1)
+#define ARPT_RETURN XT_RETURN
 
 /* The argument to ARPT_SO_GET_INFO */
 struct arpt_getinfo
@@ -208,23 +208,14 @@ struct arpt_replace
        /* Number of counters (must be equal to current number of entries). */
        unsigned int num_counters;
        /* The old entries' counters. */
-       struct arpt_counters __user *counters;
+       struct xt_counters __user *counters;
 
        /* The entries (hang off end: not really an array). */
        struct arpt_entry entries[0];
 };
 
 /* The argument to ARPT_SO_ADD_COUNTERS. */
-struct arpt_counters_info
-{
-       /* Which table. */
-       char name[ARPT_TABLE_MAXNAMELEN];
-
-       unsigned int num_counters;
-
-       /* The counters (actually `number' of these). */
-       struct arpt_counters counters[0];
-};
+#define arpt_counters_info xt_counters_info
 
 /* The argument to ARPT_SO_GET_ENTRIES. */
 struct arpt_get_entries
@@ -239,19 +230,10 @@ struct arpt_get_entries
        struct arpt_entry entrytable[0];
 };
 
-/* The argument to ARPT_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct arpt_get_revision
-{
-       char name[ARPT_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define ARPT_STANDARD_TARGET ""
+#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define ARPT_ERROR_TARGET "ERROR"
+#define ARPT_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e)
@@ -281,63 +263,8 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e
  */
 #ifdef __KERNEL__
 
-/* Registration hooks for targets. */
-struct arpt_target
-{
-       struct list_head list;
-
-       const char name[ARPT_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-
-       /* Returns verdict. */
-       unsigned int (*target)(struct sk_buff **pskb,
-                              unsigned int hooknum,
-                              const struct net_device *in,
-                              const struct net_device *out,
-                              const void *targinfo,
-                              void *userdata);
-
-       /* Called when user tries to insert an entry of this type:
-           hook_mask is a bitmask of hooks from which it can be
-           called. */
-       /* Should return true or false. */
-       int (*checkentry)(const char *tablename,
-                         const struct arpt_entry *e,
-                         void *targinfo,
-                         unsigned int targinfosize,
-                         unsigned int hook_mask);
-
-       /* Called when entry of this type deleted. */
-       void (*destroy)(void *targinfo, unsigned int targinfosize);
-
-       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
-       struct module *me;
-};
-
-extern int arpt_register_target(struct arpt_target *target);
-extern void arpt_unregister_target(struct arpt_target *target);
-
-/* Furniture shopping... */
-struct arpt_table
-{
-       struct list_head list;
-
-       /* A unique name... */
-       char name[ARPT_TABLE_MAXNAMELEN];
-
-       /* What hooks you will enter on */
-       unsigned int valid_hooks;
-
-       /* Lock for the curtain */
-       rwlock_t lock;
-
-       /* Man behind the curtain... */
-       struct arpt_table_info *private;
-
-       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
-       struct module *me;
-};
+#define arpt_register_target(tgt) xt_register_target(NF_ARP, tgt)
+#define arpt_unregister_target(tgt) xt_unregister_target(NF_ARP, tgt)
 
 extern int arpt_register_table(struct arpt_table *table,
                               const struct arpt_replace *repl);
index b3432ab59a175d23304f7dfb5739197b0168f739..215765f043e6cc23503108c9e016ae0e0058b8fe 100644 (file)
@@ -199,9 +199,6 @@ ip_conntrack_put(struct ip_conntrack *ct)
        nf_conntrack_put(&ct->ct_general);
 }
 
-/* call to create an explicit dependency on ip_conntrack. */
-extern void need_ip_conntrack(void);
-
 extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
                          const struct ip_conntrack_tuple *orig);
 
index d19d65cf453046ba28724c80f7cea09d2fda4dc0..76ba24b68515db87fb7e05ba635bb30926f4f915 100644 (file)
 #include <linux/compiler.h>
 #include <linux/netfilter_ipv4.h>
 
-#define IPT_FUNCTION_MAXNAMELEN 30
-#define IPT_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define ipt_match xt_match
+#define ipt_target xt_target
+#define ipt_table xt_table
+#define ipt_get_revision xt_get_revision
 
 /* Yes, Virginia, you have to zero the padding. */
 struct ipt_ip {
@@ -102,10 +108,7 @@ struct ipt_standard_target
        int verdict;
 };
 
-struct ipt_counters
-{
-       u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
-};
+#define ipt_counters xt_counters
 
 /* Values for "flag" field in struct ipt_ip (general ip structure). */
 #define IPT_F_FRAG             0x01    /* Set if rule is a fragment rule */
@@ -119,7 +122,7 @@ struct ipt_counters
 #define IPT_INV_SRCIP          0x08    /* Invert the sense of SRC IP. */
 #define IPT_INV_DSTIP          0x10    /* Invert the sense of DST OP. */
 #define IPT_INV_FRAG           0x20    /* Invert the sense of FRAG. */
-#define IPT_INV_PROTO          0x40    /* Invert the sense of PROTO. */
+#define IPT_INV_PROTO          XT_INV_PROTO
 #define IPT_INV_MASK           0x7F    /* All possible flag bits mask. */
 
 /* This structure defines each of the firewall rules.  Consists of 3
@@ -141,7 +144,7 @@ struct ipt_entry
        unsigned int comefrom;
 
        /* Packet and byte counters. */
-       struct ipt_counters counters;
+       struct xt_counters counters;
 
        /* The matches (if any), then the target. */
        unsigned char elems[0];
@@ -151,54 +154,34 @@ struct ipt_entry
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use a raw
  * socket for this. Instead we check rights in the calls. */
-#define IPT_BASE_CTL           64      /* base for firewall socket options */
+#define IPT_BASE_CTL           XT_BASE_CTL
 
-#define IPT_SO_SET_REPLACE     (IPT_BASE_CTL)
-#define IPT_SO_SET_ADD_COUNTERS        (IPT_BASE_CTL + 1)
-#define IPT_SO_SET_MAX         IPT_SO_SET_ADD_COUNTERS
+#define IPT_SO_SET_REPLACE     XT_SO_SET_REPLACE
+#define IPT_SO_SET_ADD_COUNTERS        XT_SO_SET_ADD_COUNTERS
+#define IPT_SO_SET_MAX         XT_SO_SET_MAX
 
-#define IPT_SO_GET_INFO                        (IPT_BASE_CTL)
-#define IPT_SO_GET_ENTRIES             (IPT_BASE_CTL + 1)
-#define IPT_SO_GET_REVISION_MATCH      (IPT_BASE_CTL + 2)
-#define IPT_SO_GET_REVISION_TARGET     (IPT_BASE_CTL + 3)
-#define IPT_SO_GET_MAX                 IPT_SO_GET_REVISION_TARGET
+#define IPT_SO_GET_INFO                        XT_SO_GET_INFO
+#define IPT_SO_GET_ENTRIES             XT_SO_GET_ENTRIES
+#define IPT_SO_GET_REVISION_MATCH      XT_SO_GET_REVISION_MATCH
+#define IPT_SO_GET_REVISION_TARGET     XT_SO_GET_REVISION_TARGET
+#define IPT_SO_GET_MAX                 XT_SO_GET_REVISION_TARGET
 
-/* CONTINUE verdict for targets */
-#define IPT_CONTINUE 0xFFFFFFFF
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
 
-/* For standard target */
-#define IPT_RETURN (-NF_REPEAT - 1)
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
 
-/* TCP matching stuff */
-struct ipt_tcp
-{
-       u_int16_t spts[2];                      /* Source port range. */
-       u_int16_t dpts[2];                      /* Destination port range. */
-       u_int8_t option;                        /* TCP Option iff non-zero*/
-       u_int8_t flg_mask;                      /* TCP flags mask byte */
-       u_int8_t flg_cmp;                       /* TCP flags compare byte */
-       u_int8_t invflags;                      /* Inverse flags */
-};
-
-/* Values for "inv" field in struct ipt_tcp. */
-#define IPT_TCP_INV_SRCPT      0x01    /* Invert the sense of source ports. */
-#define IPT_TCP_INV_DSTPT      0x02    /* Invert the sense of dest ports. */
-#define IPT_TCP_INV_FLAGS      0x04    /* Invert the sense of TCP flags. */
-#define IPT_TCP_INV_OPTION     0x08    /* Invert the sense of option test. */
-#define IPT_TCP_INV_MASK       0x0F    /* All possible flags. */
-
-/* UDP matching stuff */
-struct ipt_udp
-{
-       u_int16_t spts[2];                      /* Source port range. */
-       u_int16_t dpts[2];                      /* Destination port range. */
-       u_int8_t invflags;                      /* Inverse flags */
-};
+#define IPT_TCP_INV_SRCPT      XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT      XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS      XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION     XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK       XT_TCP_INV_MASK
 
-/* Values for "invflags" field in struct ipt_udp. */
-#define IPT_UDP_INV_SRCPT      0x01    /* Invert the sense of source ports. */
-#define IPT_UDP_INV_DSTPT      0x02    /* Invert the sense of dest ports. */
-#define IPT_UDP_INV_MASK       0x03    /* All possible flags. */
+#define IPT_UDP_INV_SRCPT      XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT      XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK       XT_UDP_INV_MASK
 
 /* ICMP matching stuff */
 struct ipt_icmp
@@ -260,23 +243,14 @@ struct ipt_replace
        /* Number of counters (must be equal to current number of entries). */
        unsigned int num_counters;
        /* The old entries' counters. */
-       struct ipt_counters __user *counters;
+       struct xt_counters __user *counters;
 
        /* The entries (hang off end: not really an array). */
        struct ipt_entry entries[0];
 };
 
 /* The argument to IPT_SO_ADD_COUNTERS. */
-struct ipt_counters_info
-{
-       /* Which table. */
-       char name[IPT_TABLE_MAXNAMELEN];
-
-       unsigned int num_counters;
-
-       /* The counters (actually `number' of these). */
-       struct ipt_counters counters[0];
-};
+#define ipt_counters_info xt_counters_info
 
 /* The argument to IPT_SO_GET_ENTRIES. */
 struct ipt_get_entries
@@ -291,19 +265,10 @@ struct ipt_get_entries
        struct ipt_entry entrytable[0];
 };
 
-/* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct ipt_get_revision
-{
-       char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define IPT_STANDARD_TARGET ""
+#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define IPT_ERROR_TARGET "ERROR"
+#define IPT_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct ipt_entry_target *
@@ -356,103 +321,18 @@ ipt_get_target(struct ipt_entry *e)
 #include <linux/init.h>
 extern void ipt_init(void) __init;
 
-struct ipt_match
-{
-       struct list_head list;
-
-       const char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-
-       /* Return true or false: return FALSE and set *hotdrop = 1 to
-           force immediate packet drop. */
-       /* Arguments changed since 2.4, as this must now handle
-           non-linear skbs, using skb_copy_bits and
-           skb_ip_make_writable. */
-       int (*match)(const struct sk_buff *skb,
-                    const struct net_device *in,
-                    const struct net_device *out,
-                    const void *matchinfo,
-                    int offset,
-                    int *hotdrop);
-
-       /* Called when user tries to insert an entry of this type. */
-       /* Should return true or false. */
-       int (*checkentry)(const char *tablename,
-                         const struct ipt_ip *ip,
-                         void *matchinfo,
-                         unsigned int matchinfosize,
-                         unsigned int hook_mask);
-
-       /* Called when entry of this type deleted. */
-       void (*destroy)(void *matchinfo, unsigned int matchinfosize);
-
-       /* Set this to THIS_MODULE. */
-       struct module *me;
-};
-
-/* Registration hooks for targets. */
-struct ipt_target
-{
-       struct list_head list;
-
-       const char name[IPT_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-
-       /* Called when user tries to insert an entry of this type:
-           hook_mask is a bitmask of hooks from which it can be
-           called. */
-       /* Should return true or false. */
-       int (*checkentry)(const char *tablename,
-                         const struct ipt_entry *e,
-                         void *targinfo,
-                         unsigned int targinfosize,
-                         unsigned int hook_mask);
-
-       /* Called when entry of this type deleted. */
-       void (*destroy)(void *targinfo, unsigned int targinfosize);
-
-       /* Returns verdict.  Argument order changed since 2.4, as this
-           must now handle non-linear skbs, using skb_copy_bits and
-           skb_ip_make_writable. */
-       unsigned int (*target)(struct sk_buff **pskb,
-                              const struct net_device *in,
-                              const struct net_device *out,
-                              unsigned int hooknum,
-                              const void *targinfo,
-                              void *userdata);
-
-       /* Set this to THIS_MODULE. */
-       struct module *me;
-};
+#define ipt_register_target(tgt) xt_register_target(AF_INET, tgt)
+#define ipt_unregister_target(tgt) xt_unregister_target(AF_INET, tgt)
 
-extern int ipt_register_target(struct ipt_target *target);
-extern void ipt_unregister_target(struct ipt_target *target);
+#define ipt_register_match(mtch) xt_register_match(AF_INET, mtch)
+#define ipt_unregister_match(mtch) xt_unregister_match(AF_INET, mtch)
 
-extern int ipt_register_match(struct ipt_match *match);
-extern void ipt_unregister_match(struct ipt_match *match);
+//#define ipt_register_table(tbl, repl) xt_register_table(AF_INET, tbl, repl)
+//#define ipt_unregister_table(tbl) xt_unregister_table(AF_INET, tbl)
 
-/* Furniture shopping... */
-struct ipt_table
-{
-       struct list_head list;
-
-       /* A unique name... */
-       char name[IPT_TABLE_MAXNAMELEN];
-
-       /* What hooks you will enter on */
-       unsigned int valid_hooks;
-
-       /* Lock for the curtain */
-       rwlock_t lock;
-
-       /* Man behind the curtain... */
-       struct ipt_table_info *private;
-
-       /* Set to THIS_MODULE. */
-       struct module *me;
-};
+extern int ipt_register_table(struct ipt_table *table,
+                             const struct ipt_replace *repl);
+extern void ipt_unregister_table(struct ipt_table *table);
 
 /* net/sched/ipt.c: Gimme access to your targets!  Gets target->me. */
 extern struct ipt_target *ipt_find_target(const char *name, u8 revision);
@@ -476,9 +356,6 @@ struct ipt_error
        struct ipt_error_target target;
 };
 
-extern int ipt_register_table(struct ipt_table *table,
-                             const struct ipt_replace *repl);
-extern void ipt_unregister_table(struct ipt_table *table);
 extern unsigned int ipt_do_table(struct sk_buff **pskb,
                                 unsigned int hook,
                                 const struct net_device *in,
@@ -486,6 +363,6 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb,
                                 struct ipt_table *table,
                                 void *userdata);
 
-#define IPT_ALIGN(s) (((s) + (__alignof__(struct ipt_entry)-1)) & ~(__alignof__(struct ipt_entry)-1))
+#define IPT_ALIGN(s) XT_ALIGN(s)
 #endif /*__KERNEL__*/
 #endif /* _IPTABLES_H */
index 7596e3dd00cad645966f7cb289cc8e3bc5d41f01..a46d511b5c363f12e5b7f90a2450377900b19015 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _IPT_CLASSIFY_H
 #define _IPT_CLASSIFY_H
 
-struct ipt_classify_target_info {
-       u_int32_t priority;
-};
+#include <linux/netfilter/xt_CLASSIFY.h>
+#define ipt_classify_target_info xt_classify_target_info
 
 #endif /*_IPT_CLASSIFY_H */
index d3c02536fc4c471063f56930673cc24a94ede8cb..9ecfee0a9e33c487d26fb9debcee984086cb9e7d 100644 (file)
@@ -9,17 +9,11 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
+#include <linux/netfilter/xt_CONNMARK.h>
+#define IPT_CONNMARK_SET       XT_CONNMARK_SET
+#define IPT_CONNMARK_SAVE      XT_CONNMARK_SAVE
+#define        IPT_CONNMARK_RESTORE    XT_CONNMARK_RESTORE
 
-enum {
-       IPT_CONNMARK_SET = 0,
-       IPT_CONNMARK_SAVE,
-       IPT_CONNMARK_RESTORE
-};
-
-struct ipt_connmark_target_info {
-       unsigned long mark;
-       unsigned long mask;
-       u_int8_t mode;
-};
+#define ipt_connmark_target_info xt_connmark_target_info
 
 #endif /*_IPT_CONNMARK_H_target*/
index f47485790ed440ea2a240500cb4874b712a2a0db..697a486a96d337aa2bdaa471b97c871ffdcff819 100644 (file)
@@ -1,20 +1,18 @@
 #ifndef _IPT_MARK_H_target
 #define _IPT_MARK_H_target
 
+/* Backwards compatibility for old userspace */
+
+#include <linux/netfilter/xt_MARK.h>
+
 /* Version 0 */
-struct ipt_mark_target_info {
-       unsigned long mark;
-};
+#define ipt_mark_target_info xt_mark_target_info
 
 /* Version 1 */
-enum {
-       IPT_MARK_SET=0,
-       IPT_MARK_AND,
-       IPT_MARK_OR
-};
+#define IPT_MARK_SET   XT_MARK_SET
+#define IPT_MARK_AND   XT_MARK_AND
+#define        IPT_MARK_OR     XT_MARK_OR
+
+#define ipt_mark_target_info_v1 xt_mark_target_info_v1
 
-struct ipt_mark_target_info_v1 {
-       unsigned long mark;
-       u_int8_t mode;
-};
 #endif /*_IPT_MARK_H_target*/
index b5b2943b0c6646b61dec2b12b49208cda310c6b0..97a2a7557cb908cbc4275a4205ef3898de58b6be 100644 (file)
@@ -8,9 +8,9 @@
 #ifndef _IPT_NFQ_TARGET_H
 #define _IPT_NFQ_TARGET_H
 
-/* target info */
-struct ipt_NFQ_info {
-       u_int16_t queuenum;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_NFQUEUE.h>
+
+#define ipt_NFQ_info xt_NFQ_info
 
 #endif /* _IPT_DSCP_TARGET_H */
index 85c1123c29ce1e026fc74961454ce1a5e0497fe9..ae2afc2f74810123f02e1f629307d5beb5e2cddf 100644 (file)
@@ -1,10 +1,10 @@
 #ifndef _IPT_COMMENT_H
 #define _IPT_COMMENT_H
 
-#define IPT_MAX_COMMENT_LEN 256
+#include <linux/netfilter/xt_comment.h>
 
-struct ipt_comment_info {
-       unsigned char comment[IPT_MAX_COMMENT_LEN];
-};
+#define IPT_MAX_COMMENT_LEN XT_MAX_COMMENT_LEN
+
+#define ipt_comment_info xt_comment_info
 
 #endif /* _IPT_COMMENT_H */
index 9e5532f8d8ac8c3595d33089e08dc6d18438a393..b04dfa3083c9527d59ceec1e6fe095ed63ebecde 100644 (file)
@@ -1,25 +1,18 @@
 #ifndef _IPT_CONNBYTES_H
 #define _IPT_CONNBYTES_H
 
-enum ipt_connbytes_what {
-       IPT_CONNBYTES_PKTS,
-       IPT_CONNBYTES_BYTES,
-       IPT_CONNBYTES_AVGPKT,
-};
+#include <net/netfilter/xt_connbytes.h>
+#define ipt_connbytes_what xt_connbytes_what
 
-enum ipt_connbytes_direction {
-       IPT_CONNBYTES_DIR_ORIGINAL,
-       IPT_CONNBYTES_DIR_REPLY,
-       IPT_CONNBYTES_DIR_BOTH,
-};
+#define IPT_CONNBYTES_PKTS     XT_CONNBYTES_PACKETS
+#define IPT_CONNBYTES_BYTES    XT_CONNBYTES_BYTES
+#define IPT_CONNBYTES_AVGPKT   XT_CONNBYTES_AVGPKT
+
+#define ipt_connbytes_direction        xt_connbytes_direction
+#define IPT_CONNBYTES_DIR_ORIGINAL     XT_CONNBYTES_DIR_ORIGINAL
+#define IPT_CONNBYTES_DIR_REPLY        XT_CONNBYTES_DIR_REPLY
+#define IPT_CONNBYTES_DIR_BOTH         XT_CONNBYTES_DIR_BOTH
+
+#define ipt_connbytes_info xt_connbytes_info
 
-struct ipt_connbytes_info
-{
-       struct {
-               aligned_u64 from;       /* count to be matched */
-               aligned_u64 to;         /* count to be matched */
-       } count;
-       u_int8_t what;          /* ipt_connbytes_what */
-       u_int8_t direction;     /* ipt_connbytes_direction */
-};
 #endif
index 46573270d9aa23781d0d2dd4a2bbf3688149b24b..c7ba6560d44c5d196322de703502c4dc71852730 100644 (file)
@@ -1,18 +1,7 @@
 #ifndef _IPT_CONNMARK_H
 #define _IPT_CONNMARK_H
 
-/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
- * by Henrik Nordstrom <hno@marasystems.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.
- */
-
-struct ipt_connmark_info {
-       unsigned long mark, mask;
-       u_int8_t invert;
-};
+#include <linux/netfilter/xt_connmark.h>
+#define ipt_connmark_info xt_connmark_info
 
 #endif /*_IPT_CONNMARK_H*/
index 413c5658bd3adc7b2041107abc53b4b9f1ad48b6..cde6762949c5b4d4462cde281fc71325db3a9c57 100644 (file)
@@ -5,56 +5,24 @@
 #ifndef _IPT_CONNTRACK_H
 #define _IPT_CONNTRACK_H
 
-#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
-#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
+#include <linux/netfilter/xt_conntrack.h>
 
-#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
-#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
-#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
+#define IPT_CONNTRACK_STATE_BIT(ctinfo) XT_CONNTRACK_STATE_BIT(ctinfo)
+#define IPT_CONNTRACK_STATE_INVALID    XT_CONNTRACK_STATE_INVALID
 
-/* flags, invflags: */
-#define IPT_CONNTRACK_STATE    0x01
-#define IPT_CONNTRACK_PROTO    0x02
-#define IPT_CONNTRACK_ORIGSRC  0x04
-#define IPT_CONNTRACK_ORIGDST  0x08
-#define IPT_CONNTRACK_REPLSRC  0x10
-#define IPT_CONNTRACK_REPLDST  0x20
-#define IPT_CONNTRACK_STATUS   0x40
-#define IPT_CONNTRACK_EXPIRES  0x80
-
-/* This is exposed to userspace, so remains frozen in time. */
-struct ip_conntrack_old_tuple
-{
-       struct {
-               __u32 ip;
-               union {
-                       __u16 all;
-               } u;
-       } src;
-
-       struct {
-               __u32 ip;
-               union {
-                       __u16 all;
-               } u;
-
-               /* The protocol. */
-               u16 protonum;
-       } dst;
-};
+#define IPT_CONNTRACK_STATE_SNAT       XT_CONNTRACK_STATE_SNAT
+#define IPT_CONNTRACK_STATE_DNAT       XT_CONNTRACK_STATE_DNAT
+#define IPT_CONNTRACK_STATE_UNTRACKED  XT_CONNTRACK_STATE_UNTRACKED
 
-struct ipt_conntrack_info
-{
-       unsigned int statemask, statusmask;
-
-       struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
-       struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
-
-       unsigned long expires_min, expires_max;
-
-       /* Flags word */
-       u_int8_t flags;
-       /* Inverse flags */
-       u_int8_t invflags;
-};
+/* flags, invflags: */
+#define IPT_CONNTRACK_STATE            XT_CONNTRACK_STATE
+#define IPT_CONNTRACK_PROTO            XT_CONNTRACK_PROTO
+#define IPT_CONNTRACK_ORIGSRC          XT_CONNTRACK_ORIGSRC
+#define IPT_CONNTRACK_ORIGDST          XT_CONNTRACK_ORIGDST
+#define IPT_CONNTRACK_REPLSRC          XT_CONNTRACK_REPLSRC
+#define IPT_CONNTRACK_REPLDST          XT_CONNTRACK_REPLDST
+#define IPT_CONNTRACK_STATUS           XT_CONNTRACK_STATUS
+#define IPT_CONNTRACK_EXPIRES          XT_CONNTRACK_EXPIRES
+
+#define ipt_conntrack_info             xt_conntrack_info
 #endif /*_IPT_CONNTRACK_H*/
index 3cb3a522e62b78cd32ecbcaee5a6a65816ae1822..e70d11e1f53cf8018805f7ecd5d12e12a22989e8 100644 (file)
@@ -1,23 +1,15 @@
 #ifndef _IPT_DCCP_H_
 #define _IPT_DCCP_H_
 
-#define IPT_DCCP_SRC_PORTS             0x01
-#define IPT_DCCP_DEST_PORTS            0x02
-#define IPT_DCCP_TYPE                  0x04
-#define IPT_DCCP_OPTION                        0x08
+#include <linux/netfilter/xt_dccp.h>
+#define IPT_DCCP_SRC_PORTS     XT_DCCP_SRC_PORTS
+#define IPT_DCCP_DEST_PORTS    XT_DCCP_DEST_PORTS
+#define IPT_DCCP_TYPE          XT_DCCP_TYPE
+#define IPT_DCCP_OPTION                XT_DCCP_OPTION
 
-#define IPT_DCCP_VALID_FLAGS           0x0f
+#define IPT_DCCP_VALID_FLAGS   XT_DCCP_VALID_FLAGS
 
-struct ipt_dccp_info {
-       u_int16_t dpts[2];  /* Min, Max */
-       u_int16_t spts[2];  /* Min, Max */
-
-       u_int16_t flags;
-       u_int16_t invflags;
-
-       u_int16_t typemask;
-       u_int8_t option;
-};
+#define ipt_dccp_info xt_dccp_info
 
 #endif /* _IPT_DCCP_H_ */
 
index 6f12ecb8c93df8d48dc9907b0ab5688f1a4f2a37..80452c218551f172dc61c77e2ba0eea588aa3cd3 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _IPT_HELPER_H
 #define _IPT_HELPER_H
 
-struct ipt_helper_info {
-       int invert;
-       char name[30];
-};
+#include <linux/netfilter/xt_helper.h>
+#define ipt_helper_info xt_helper_info
+
 #endif /* _IPT_HELPER_H */
index 6e0885229615c22c7e85963315462e5d5c33dff2..9b45206ffcef75610e5804a91ba5e4deedad4f08 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef _IPT_LENGTH_H
 #define _IPT_LENGTH_H
 
-struct ipt_length_info {
-    u_int16_t  min, max;
-    u_int8_t   invert;
-};
+#include <linux/netfilter/xt_length.h>
+#define ipt_length_info xt_length_info
 
 #endif /*_IPT_LENGTH_H*/
index 256453409e21f87b26a623fb18a3fb05b45d781f..92f5cd07bbc40d45948fed145029a3a0ded7b3a2 100644 (file)
@@ -1,21 +1,8 @@
 #ifndef _IPT_RATE_H
 #define _IPT_RATE_H
 
-/* timings are in milliseconds. */
-#define IPT_LIMIT_SCALE 10000
+#include <linux/netfilter/xt_limit.h>
+#define IPT_LIMIT_SCALE XT_LIMIT_SCALE
+#define ipt_rateinfo xt_rateinfo
 
-/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
-   seconds, or one every 59 hours. */
-struct ipt_rateinfo {
-       u_int32_t avg;    /* Average secs between packets * scale */
-       u_int32_t burst;  /* Period multiplier for upper limit. */
-
-       /* Used internally by the kernel */
-       unsigned long prev;
-       u_int32_t credit;
-       u_int32_t credit_cap, cost;
-
-       /* Ugly, ugly fucker. */
-       struct ipt_rateinfo *master;
-};
 #endif /*_IPT_RATE_H*/
index f8d5b8e7ccdb69a6d8dad214fab1761c94735f2a..b186008a3c477df76921b6c92bff305d439dec54 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _IPT_MAC_H
 #define _IPT_MAC_H
 
-struct ipt_mac_info {
-    unsigned char srcaddr[ETH_ALEN];
-    int invert;
-};
+#include <linux/netfilter/xt_mac.h>
+#define ipt_mac_info xt_mac_info
+
 #endif /*_IPT_MAC_H*/
index f3952b563d4cbceb53f2da2c8192cc9e433943f6..bfde67c6122484bf9126b6a0e9997accaa19ecda 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef _IPT_MARK_H
 #define _IPT_MARK_H
 
-struct ipt_mark_info {
-    unsigned long mark, mask;
-    u_int8_t invert;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_mark.h>
+
+#define ipt_mark_info xt_mark_info
 
 #endif /*_IPT_MARK_H*/
index 7538c8655ec046cdd99fd417fdf3d9d31c84990b..2400e7140f26e7afb669a7b67473bb84c4c1e2ac 100644 (file)
@@ -1,24 +1,17 @@
 #ifndef _IPT_PHYSDEV_H
 #define _IPT_PHYSDEV_H
 
-#ifdef __KERNEL__
-#include <linux/if.h>
-#endif
+/* Backwards compatibility for old userspace */
 
-#define IPT_PHYSDEV_OP_IN              0x01
-#define IPT_PHYSDEV_OP_OUT             0x02
-#define IPT_PHYSDEV_OP_BRIDGED         0x04
-#define IPT_PHYSDEV_OP_ISIN            0x08
-#define IPT_PHYSDEV_OP_ISOUT           0x10
-#define IPT_PHYSDEV_OP_MASK            (0x20 - 1)
+#include <linux/netfilter/xt_physdev.h>
 
-struct ipt_physdev_info {
-       char physindev[IFNAMSIZ];
-       char in_mask[IFNAMSIZ];
-       char physoutdev[IFNAMSIZ];
-       char out_mask[IFNAMSIZ];
-       u_int8_t invert;
-       u_int8_t bitmask;
-};
+#define IPT_PHYSDEV_OP_IN              XT_PHYSDEV_OP_IN
+#define IPT_PHYSDEV_OP_OUT             XT_PHYSDEV_OP_OUT
+#define IPT_PHYSDEV_OP_BRIDGED         XT_PHYSDEV_OP_BRIDGED
+#define IPT_PHYSDEV_OP_ISIN            XT_PHYSDEV_OP_ISIN
+#define IPT_PHYSDEV_OP_ISOUT           XT_PHYSDEV_OP_ISOUT
+#define IPT_PHYSDEV_OP_MASK            XT_PHYSDEV_OP_MASK
+
+#define ipt_physdev_info xt_physdev_info
 
 #endif /*_IPT_PHYSDEV_H*/
index d53a65848683ccf97f214a889d77d839ac87f808..ff1fbc949a0c2e7c9ab0efa81b95188f208e7568 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _IPT_PKTTYPE_H
 #define _IPT_PKTTYPE_H
 
-struct ipt_pkttype_info {
-       int     pkttype;
-       int     invert;
-};
+#include <linux/netfilter/xt_pkttype.h>
+#define ipt_pkttype_info xt_pkttype_info
+
 #endif /*_IPT_PKTTYPE_H*/
index a4d6698723acf280c77cc362ab0d8f9396d5433b..b3996eaa0188aa1352e13699256e92ffa6f32edf 100644 (file)
@@ -1,10 +1,7 @@
 #ifndef _IPT_REALM_H
 #define _IPT_REALM_H
 
-struct ipt_realm_info {
-       u_int32_t id;
-       u_int32_t mask;
-       u_int8_t invert;
-};
+#include <linux/netfilter/xt_realm.h>
+#define ipt_realm_info xt_realm_info
 
 #endif /* _IPT_REALM_H */
index 5df37868933d9d91795dff8728f0b7a9c6000d81..a44a99cc28ccd2434d42d5b916bcf8d518a01aca 100644 (file)
@@ -1,13 +1,15 @@
 #ifndef _IPT_STATE_H
 #define _IPT_STATE_H
 
-#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
-#define IPT_STATE_INVALID (1 << 0)
+/* Backwards compatibility for old userspace */
 
-#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
+#include <linux/netfilter/xt_state.h>
+
+#define IPT_STATE_BIT          XT_STATE_BIT
+#define IPT_STATE_INVALID      XT_STATE_INVALID
+
+#define IPT_STATE_UNTRACKED    XT_STATE_UNTRACKED
+
+#define ipt_state_info         xt_state_info
 
-struct ipt_state_info
-{
-       unsigned int statemask;
-};
 #endif /*_IPT_STATE_H*/
index a265f6e44eabc0f54d27a8062b9803d5ff21a2c1..c26de3059903eeb21a91de18c067db084de67a68 100644 (file)
@@ -1,18 +1,10 @@
 #ifndef _IPT_STRING_H
 #define _IPT_STRING_H
 
-#define IPT_STRING_MAX_PATTERN_SIZE 128
-#define IPT_STRING_MAX_ALGO_NAME_SIZE 16
+#include <linux/netfilter/xt_string.h>
 
-struct ipt_string_info
-{
-       u_int16_t from_offset;
-       u_int16_t to_offset;
-       char      algo[IPT_STRING_MAX_ALGO_NAME_SIZE];
-       char      pattern[IPT_STRING_MAX_PATTERN_SIZE];
-       u_int8_t  patlen;
-       u_int8_t  invert;
-       struct ts_config __attribute__((aligned(8))) *config;
-};
+#define IPT_STRING_MAX_PATTERN_SIZE XT_STRING_MAX_PATTERN_SIZE
+#define IPT_STRING_MAX_ALGO_NAME_SIZE XT_STRING_MAX_ALGO_NAME_SIZE
+#define ipt_string_info xt_string_info
 
 #endif /*_IPT_STRING_H*/
index e2b14397f701b72e858ea942607a3c19176e5eb0..18bbc8e8e00937b67df04d661791fb5a58094541 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef _IPT_TCPMSS_MATCH_H
 #define _IPT_TCPMSS_MATCH_H
 
-struct ipt_tcpmss_match_info {
-    u_int16_t mss_min, mss_max;
-    u_int8_t invert;
-};
+#include <linux/netfilter/xt_tcpmss.h>
+#define ipt_tcpmss_match_info xt_tcpmss_match_info
 
 #endif /*_IPT_TCPMSS_MATCH_H*/
index c163ba31aab7bc82745ab8d27f54ff7932ea4f21..f249b574f0fa0e5ef8cb7fb2ff4cc1fcd7c2278b 100644 (file)
 #include <linux/compiler.h>
 #include <linux/netfilter_ipv6.h>
 
-#define IP6T_FUNCTION_MAXNAMELEN 30
-#define IP6T_TABLE_MAXNAMELEN 32
+#include <linux/netfilter/x_tables.h>
+
+#define IP6T_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IP6T_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+
+#define ip6t_match xt_match
+#define ip6t_target xt_target
+#define ip6t_table xt_table
+#define ip6t_get_revision xt_get_revision
 
 /* Yes, Virginia, you have to zero the padding. */
 struct ip6t_ip6 {
@@ -104,10 +111,7 @@ struct ip6t_standard_target
        int verdict;
 };
 
-struct ip6t_counters
-{
-       u_int64_t pcnt, bcnt;                   /* Packet and byte counters */
-};
+#define ip6t_counters  xt_counters
 
 /* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
 #define IP6T_F_PROTO           0x01    /* Set if rule cares about upper 
@@ -123,7 +127,7 @@ struct ip6t_counters
 #define IP6T_INV_SRCIP         0x08    /* Invert the sense of SRC IP. */
 #define IP6T_INV_DSTIP         0x10    /* Invert the sense of DST OP. */
 #define IP6T_INV_FRAG          0x20    /* Invert the sense of FRAG. */
-#define IP6T_INV_PROTO         0x40    /* Invert the sense of PROTO. */
+#define IP6T_INV_PROTO         XT_INV_PROTO
 #define IP6T_INV_MASK          0x7F    /* All possible flag bits mask. */
 
 /* This structure defines each of the firewall rules.  Consists of 3
@@ -145,7 +149,7 @@ struct ip6t_entry
        unsigned int comefrom;
 
        /* Packet and byte counters. */
-       struct ip6t_counters counters;
+       struct xt_counters counters;
 
        /* The matches (if any), then the target. */
        unsigned char elems[0];
@@ -155,54 +159,41 @@ struct ip6t_entry
  * New IP firewall options for [gs]etsockopt at the RAW IP level.
  * Unlike BSD Linux inherits IP options so you don't have to use
  * a raw socket for this. Instead we check rights in the calls. */
-#define IP6T_BASE_CTL                  64      /* base for firewall socket options */
+#define IP6T_BASE_CTL                  XT_BASE_CTL
 
-#define IP6T_SO_SET_REPLACE            (IP6T_BASE_CTL)
-#define IP6T_SO_SET_ADD_COUNTERS       (IP6T_BASE_CTL + 1)
-#define IP6T_SO_SET_MAX                        IP6T_SO_SET_ADD_COUNTERS
+#define IP6T_SO_SET_REPLACE            XT_SO_SET_REPLACE
+#define IP6T_SO_SET_ADD_COUNTERS       XT_SO_SET_ADD_COUNTERS
+#define IP6T_SO_SET_MAX                        XT_SO_SET_MAX
 
-#define IP6T_SO_GET_INFO               (IP6T_BASE_CTL)
-#define IP6T_SO_GET_ENTRIES            (IP6T_BASE_CTL + 1)
-#define        IP6T_SO_GET_REVISION_MATCH      (IP6T_BASE_CTL + 2)
-#define        IP6T_SO_GET_REVISION_TARGET     (IP6T_BASE_CTL + 3)
-#define IP6T_SO_GET_MAX                        IP6T_SO_GET_REVISION_TARGET
+#define IP6T_SO_GET_INFO               XT_SO_GET_INFO
+#define IP6T_SO_GET_ENTRIES            XT_SO_GET_ENTRIES
+#define        IP6T_SO_GET_REVISION_MATCH      XT_SO_GET_REVISION_MATCH
+#define        IP6T_SO_GET_REVISION_TARGET     XT_SO_GET_REVISION_TARGET
+#define IP6T_SO_GET_MAX                        XT_SO_GET_REVISION_TARGET
 
 /* CONTINUE verdict for targets */
-#define IP6T_CONTINUE 0xFFFFFFFF
+#define IP6T_CONTINUE XT_CONTINUE
 
 /* For standard target */
-#define IP6T_RETURN (-NF_REPEAT - 1)
+#define IP6T_RETURN XT_RETURN
 
-/* TCP matching stuff */
-struct ip6t_tcp
-{
-       u_int16_t spts[2];                      /* Source port range. */
-       u_int16_t dpts[2];                      /* Destination port range. */
-       u_int8_t option;                        /* TCP Option iff non-zero*/
-       u_int8_t flg_mask;                      /* TCP flags mask byte */
-       u_int8_t flg_cmp;                       /* TCP flags compare byte */
-       u_int8_t invflags;                      /* Inverse flags */
-};
+/* TCP/UDP matching stuff */
+#include <linux/netfilter/xt_tcpudp.h>
+
+#define ip6t_tcp xt_tcp
+#define ip6t_udp xt_udp
 
 /* Values for "inv" field in struct ipt_tcp. */
-#define IP6T_TCP_INV_SRCPT     0x01    /* Invert the sense of source ports. */
-#define IP6T_TCP_INV_DSTPT     0x02    /* Invert the sense of dest ports. */
-#define IP6T_TCP_INV_FLAGS     0x04    /* Invert the sense of TCP flags. */
-#define IP6T_TCP_INV_OPTION    0x08    /* Invert the sense of option test. */
-#define IP6T_TCP_INV_MASK      0x0F    /* All possible flags. */
-
-/* UDP matching stuff */
-struct ip6t_udp
-{
-       u_int16_t spts[2];                      /* Source port range. */
-       u_int16_t dpts[2];                      /* Destination port range. */
-       u_int8_t invflags;                      /* Inverse flags */
-};
+#define IP6T_TCP_INV_SRCPT     XT_TCP_INV_SRCPT
+#define IP6T_TCP_INV_DSTPT     XT_TCP_INV_DSTPT
+#define IP6T_TCP_INV_FLAGS     XT_TCP_INV_FLAGS
+#define IP6T_TCP_INV_OPTION    XT_TCP_INV_OPTION
+#define IP6T_TCP_INV_MASK      XT_TCP_INV_MASK
 
 /* Values for "invflags" field in struct ipt_udp. */
-#define IP6T_UDP_INV_SRCPT     0x01    /* Invert the sense of source ports. */
-#define IP6T_UDP_INV_DSTPT     0x02    /* Invert the sense of dest ports. */
-#define IP6T_UDP_INV_MASK      0x03    /* All possible flags. */
+#define IP6T_UDP_INV_SRCPT     XT_UDP_INV_SRCPT
+#define IP6T_UDP_INV_DSTPT     XT_UDP_INV_DSTPT
+#define IP6T_UDP_INV_MASK      XT_UDP_INV_MASK
 
 /* ICMP matching stuff */
 struct ip6t_icmp
@@ -264,23 +255,14 @@ struct ip6t_replace
        /* Number of counters (must be equal to current number of entries). */
        unsigned int num_counters;
        /* The old entries' counters. */
-       struct ip6t_counters __user *counters;
+       struct xt_counters __user *counters;
 
        /* The entries (hang off end: not really an array). */
        struct ip6t_entry entries[0];
 };
 
 /* The argument to IP6T_SO_ADD_COUNTERS. */
-struct ip6t_counters_info
-{
-       /* Which table. */
-       char name[IP6T_TABLE_MAXNAMELEN];
-
-       unsigned int num_counters;
-
-       /* The counters (actually `number' of these). */
-       struct ip6t_counters counters[0];
-};
+#define ip6t_counters_info xt_counters_info
 
 /* The argument to IP6T_SO_GET_ENTRIES. */
 struct ip6t_get_entries
@@ -295,19 +277,10 @@ struct ip6t_get_entries
        struct ip6t_entry entrytable[0];
 };
 
-/* The argument to IP6T_SO_GET_REVISION_*.  Returns highest revision
- * kernel supports, if >= revision. */
-struct ip6t_get_revision
-{
-       char name[IP6T_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-};
-
 /* Standard return verdict, or do jump. */
-#define IP6T_STANDARD_TARGET ""
+#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
 /* Error verdict. */
-#define IP6T_ERROR_TARGET "ERROR"
+#define IP6T_ERROR_TARGET XT_ERROR_TARGET
 
 /* Helper functions */
 static __inline__ struct ip6t_entry_target *
@@ -361,104 +334,11 @@ ip6t_get_target(struct ip6t_entry *e)
 #include <linux/init.h>
 extern void ip6t_init(void) __init;
 
-struct ip6t_match
-{
-       struct list_head list;
-
-       const char name[IP6T_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-
-       /* Return true or false: return FALSE and set *hotdrop = 1 to
-           force immediate packet drop. */
-       /* Arguments changed since 2.6.9, as this must now handle
-          non-linear skb, using skb_header_pointer and
-          skb_ip_make_writable. */
-       int (*match)(const struct sk_buff *skb,
-                    const struct net_device *in,
-                    const struct net_device *out,
-                    const void *matchinfo,
-                    int offset,
-                    unsigned int protoff,
-                    int *hotdrop);
-
-       /* Called when user tries to insert an entry of this type. */
-       /* Should return true or false. */
-       int (*checkentry)(const char *tablename,
-                         const struct ip6t_ip6 *ip,
-                         void *matchinfo,
-                         unsigned int matchinfosize,
-                         unsigned int hook_mask);
-
-       /* Called when entry of this type deleted. */
-       void (*destroy)(void *matchinfo, unsigned int matchinfosize);
-
-       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
-       struct module *me;
-};
-
-/* Registration hooks for targets. */
-struct ip6t_target
-{
-       struct list_head list;
-
-       const char name[IP6T_FUNCTION_MAXNAMELEN-1];
-
-       u_int8_t revision;
-
-       /* Returns verdict. Argument order changed since 2.6.9, as this
-          must now handle non-linear skbs, using skb_copy_bits and
-          skb_ip_make_writable. */
-       unsigned int (*target)(struct sk_buff **pskb,
-                              const struct net_device *in,
-                              const struct net_device *out,
-                              unsigned int hooknum,
-                              const void *targinfo,
-                              void *userdata);
-
-       /* Called when user tries to insert an entry of this type:
-           hook_mask is a bitmask of hooks from which it can be
-           called. */
-       /* Should return true or false. */
-       int (*checkentry)(const char *tablename,
-                         const struct ip6t_entry *e,
-                         void *targinfo,
-                         unsigned int targinfosize,
-                         unsigned int hook_mask);
-
-       /* Called when entry of this type deleted. */
-       void (*destroy)(void *targinfo, unsigned int targinfosize);
-
-       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
-       struct module *me;
-};
-
-extern int ip6t_register_target(struct ip6t_target *target);
-extern void ip6t_unregister_target(struct ip6t_target *target);
-
-extern int ip6t_register_match(struct ip6t_match *match);
-extern void ip6t_unregister_match(struct ip6t_match *match);
+#define ip6t_register_target(tgt) xt_register_target(AF_INET6, tgt)
+#define ip6t_unregister_target(tgt) xt_unregister_target(AF_INET6, tgt)
 
-/* Furniture shopping... */
-struct ip6t_table
-{
-       struct list_head list;
-
-       /* A unique name... */
-       char name[IP6T_TABLE_MAXNAMELEN];
-
-       /* What hooks you will enter on */
-       unsigned int valid_hooks;
-
-       /* Lock for the curtain */
-       rwlock_t lock;
-
-       /* Man behind the curtain... */
-       struct ip6t_table_info *private;
-
-       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
-       struct module *me;
-};
+#define ip6t_register_match(match) xt_register_match(AF_INET6, match)
+#define ip6t_unregister_match(match) xt_unregister_match(AF_INET6, match)
 
 extern int ip6t_register_table(struct ip6t_table *table,
                               const struct ip6t_replace *repl);
index 7ade8d8f52468c5725249b296ab55a62d89f1cae..7cf629a8ab923a296eb46b4d3c1e315919f854ac 100644 (file)
@@ -1,8 +1,9 @@
 #ifndef _IP6T_MARK_H_target
 #define _IP6T_MARK_H_target
 
-struct ip6t_mark_target_info {
-       unsigned long mark;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_MARK.h>
 
-#endif /*_IPT_MARK_H_target*/
+#define ip6t_mark_target_info xt_mark_target_info
+
+#endif /*_IP6T_MARK_H_target*/
index 7fc09f9f9d639c85d530766d82e40f78d20944e9..9e9689d03ed742d5422198afc4041a09154f2f36 100644 (file)
@@ -1,10 +1,8 @@
 #ifndef _IP6T_LENGTH_H
 #define _IP6T_LENGTH_H
 
-struct ip6t_length_info {
-       u_int16_t  min, max;
-       u_int8_t   invert;
-};
+#include <linux/netfilter/xt_length.h>
+#define ip6t_length_info xt_length_info
 
 #endif /*_IP6T_LENGTH_H*/
        
index f2866e50f3b446ad3e233f950ccf777514502942..487e5ea342c6e1366976f0caaa6e79f9e1229ed2 100644 (file)
@@ -1,21 +1,8 @@
 #ifndef _IP6T_RATE_H
 #define _IP6T_RATE_H
 
-/* timings are in milliseconds. */
-#define IP6T_LIMIT_SCALE 10000
+#include <linux/netfilter/xt_limit.h>
+#define IP6T_LIMIT_SCALE XT_LIMIT_SCALE
+#define ip6t_rateinfo xt_rateinfo
 
-/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
-   seconds, or one every 59 hours. */
-struct ip6t_rateinfo {
-       u_int32_t avg;    /* Average secs between packets * scale */
-       u_int32_t burst;  /* Period multiplier for upper limit. */
-
-       /* Used internally by the kernel */
-       unsigned long prev;
-       u_int32_t credit;
-       u_int32_t credit_cap, cost;
-
-       /* Ugly, ugly fucker. */
-       struct ip6t_rateinfo *master;
-};
-#endif /*_IPT_RATE_H*/
+#endif /*_IP6T_RATE_H*/
index 87c088c21848e23bc8efa86fbbdcf67e200b4fd6..ac58e83e9423e7556273e84f0ae39d52c921ae48 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _IP6T_MAC_H
 #define _IP6T_MAC_H
 
-struct ip6t_mac_info {
-    unsigned char srcaddr[ETH_ALEN];
-    int invert;
-};
-#endif /*_IPT_MAC_H*/
+#include <linux/netfilter/xt_mac.h>
+#define ip6t_mac_info xt_mac_info
+
+#endif /*_IP6T_MAC_H*/
index a734441e1c19a581d32c35b979f591ece86c895f..ff204951ddc3ad4196c5f1d42eb6bcb86cfaf739 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef _IP6T_MARK_H
 #define _IP6T_MARK_H
 
-struct ip6t_mark_info {
-    unsigned long mark, mask;
-    u_int8_t invert;
-};
+/* Backwards compatibility for old userspace */
+#include <linux/netfilter/xt_mark.h>
+
+#define ip6t_mark_info xt_mark_info
 
 #endif /*_IPT_MARK_H*/
index c234731cd66bc33f7f1450f389b62090365d7aae..c161c0a81b55d458fa5db0ab87814acf3c46b86d 100644 (file)
@@ -1,24 +1,17 @@
 #ifndef _IP6T_PHYSDEV_H
 #define _IP6T_PHYSDEV_H
 
-#ifdef __KERNEL__
-#include <linux/if.h>
-#endif
+/* Backwards compatibility for old userspace */
 
-#define IP6T_PHYSDEV_OP_IN             0x01
-#define IP6T_PHYSDEV_OP_OUT            0x02
-#define IP6T_PHYSDEV_OP_BRIDGED                0x04
-#define IP6T_PHYSDEV_OP_ISIN           0x08
-#define IP6T_PHYSDEV_OP_ISOUT          0x10
-#define IP6T_PHYSDEV_OP_MASK           (0x20 - 1)
+#include <linux/netfilter/xt_physdev.h>
 
-struct ip6t_physdev_info {
-       char physindev[IFNAMSIZ];
-       char in_mask[IFNAMSIZ];
-       char physoutdev[IFNAMSIZ];
-       char out_mask[IFNAMSIZ];
-       u_int8_t invert;
-       u_int8_t bitmask;
-};
+#define IP6T_PHYSDEV_OP_IN             XT_PHYSDEV_OP_IN
+#define IP6T_PHYSDEV_OP_OUT            XT_PHYSDEV_OP_OUT
+#define IP6T_PHYSDEV_OP_BRIDGED                XT_PHYSDEV_OP_BRIDGED
+#define IP6T_PHYSDEV_OP_ISIN           XT_PHYSDEV_OP_ISIN
+#define IP6T_PHYSDEV_OP_ISOUT          XT_PHYSDEV_OP_ISOUT
+#define IP6T_PHYSDEV_OP_MASK           XT_PHYSDEV_OP_MASK
+
+#define ip6t_physdev_info xt_physdev_info
 
 #endif /*_IP6T_PHYSDEV_H*/
index 7fb397e3f2d339f198fed3b08cd60a58e6927f5b..5403257ae3e7173218186453cb0141a3b87d71ca 100644 (file)
 #define PCI_DEVICE_ID_LSI_FC929X       0x0626
 #define PCI_DEVICE_ID_LSI_FC939X       0x0642
 #define PCI_DEVICE_ID_LSI_FC949X       0x0640
+#define PCI_DEVICE_ID_LSI_FC949ES      0x0646
 #define PCI_DEVICE_ID_LSI_FC919X       0x0628
 #define PCI_DEVICE_ID_NCR_YELLOWFIN    0x0701
 #define PCI_DEVICE_ID_LSI_61C102       0x0901
index 74488e49166d88c40018c91f247e5873ad842510..aa6322d4519828c4598cbab4c07116a2a615c385 100644 (file)
@@ -146,6 +146,11 @@ struct property;
 extern void proc_device_tree_init(void);
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
 extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
+extern void proc_device_tree_remove_prop(struct proc_dir_entry *pde,
+                                        struct property *prop);
+extern void proc_device_tree_update_prop(struct proc_dir_entry *pde,
+                                        struct property *newprop,
+                                        struct property *oldprop);
 #endif /* CONFIG_PROC_DEVICETREE */
 
 extern struct proc_dir_entry *proc_symlink(const char *,
index 48831eac291075b31cb45d766cc8f76b6c9cdaac..d0dd38b3a2fd8b0c14ea47d540eb4de9361080b5 100644 (file)
@@ -31,9 +31,11 @@ enum raid_level {
        RAID_LEVEL_LINEAR,
        RAID_LEVEL_0,
        RAID_LEVEL_1,
+       RAID_LEVEL_10,
        RAID_LEVEL_3,
        RAID_LEVEL_4,
        RAID_LEVEL_5,
+       RAID_LEVEL_50,
        RAID_LEVEL_6,
 };
 
index a72e17135421890ec73b11c8b89404652a6e6b43..2df1a1a2fee5215deaa6fbbfcc8b4e37cbeff3bc 100644 (file)
@@ -160,6 +160,7 @@ extern unsigned long nr_iowait(void);
 #define SCHED_NORMAL           0
 #define SCHED_FIFO             1
 #define SCHED_RR               2
+#define SCHED_BATCH            3
 
 struct sched_param {
        int sched_priority;
@@ -470,9 +471,9 @@ struct signal_struct {
 
 /*
  * Priority of a process goes from 0..MAX_PRIO-1, valid RT
- * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL tasks are
- * in the range MAX_RT_PRIO..MAX_PRIO-1. Priority values
- * are inverted: lower p->prio value means higher priority.
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
+ * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
+ * values are inverted: lower p->prio value means higher priority.
  *
  * The MAX_USER_RT_PRIO value allows the actual maximum
  * RT priority to be separate from the value exported to
index a8187c3c8a7b0606d4358ba392997011ea73d04c..ec351005bf9d9ccb5c521a9048dfdcad7c2db57b 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
+#include <linux/mutex.h>
 
 struct uart_port;
 struct uart_info;
@@ -284,7 +285,7 @@ struct uart_state {
        struct uart_info        *info;
        struct uart_port        *port;
 
-       struct semaphore        sem;
+       struct mutex            mutex;
 };
 
 #define UART_XMIT_SIZE PAGE_SIZE
index c3e598276e78ea5d30990c0f4122e553352c4db2..c057f0b32318bdc40ea879086805e174db29c035 100644 (file)
@@ -26,6 +26,8 @@ struct shmem_sb_info {
        unsigned long free_blocks;  /* How many are left for allocation */
        unsigned long max_inodes;   /* How many inodes are allowed */
        unsigned long free_inodes;  /* How many are left for allocation */
+       int policy;                 /* Default NUMA memory alloc policy */
+       nodemask_t policy_nodes;    /* nodemask for preferred and bind */
        spinlock_t    stat_lock;
 };
 
index c4153120ade634391c295eb97d6a046d2ba23b90..621a3d3662f328c13c742a96b325307d8dc583e5 100644 (file)
@@ -58,53 +58,6 @@ static inline struct smb_inode_info *SMB_I(struct inode *inode)
 /* where to find the base of the SMB packet proper */
 #define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
 
-#ifdef DEBUG_SMB_MALLOC
-
-#include <linux/slab.h>
-
-extern int smb_malloced;
-extern int smb_current_vmalloced;
-extern int smb_current_kmalloced;
-
-static inline void *
-smb_vmalloc(unsigned int size)
-{
-        smb_malloced += 1;
-        smb_current_vmalloced += 1;
-        return vmalloc(size);
-}
-
-static inline void
-smb_vfree(void *obj)
-{
-        smb_current_vmalloced -= 1;
-        vfree(obj);
-}
-
-static inline void *
-smb_kmalloc(size_t size, int flags)
-{
-       smb_malloced += 1;
-       smb_current_kmalloced += 1;
-       return kmalloc(size, flags);
-}
-
-static inline void
-smb_kfree(void *obj)
-{
-       smb_current_kmalloced -= 1;
-       kfree(obj);
-}
-
-#else /* DEBUG_SMB_MALLOC */
-
-#define smb_kmalloc(s,p)       kmalloc(s,p)
-#define smb_kfree(o)           kfree(o)
-#define smb_vmalloc(s)         vmalloc(s)
-#define smb_vfree(o)           vfree(o)
-
-#endif /* DEBUG_SMB_MALLOC */
-
 /*
  * Flags for the in-memory inode
  */
index 9f4019156fd8e7045e442df7f7661d7032b0642e..b02dda4ee83d113f6e4783ba02a68629593fe5d9 100644 (file)
@@ -186,6 +186,7 @@ struct ucred {
 #define AF_PPPOX       24      /* PPPoX sockets                */
 #define AF_WANPIPE     25      /* Wanpipe API Sockets */
 #define AF_LLC         26      /* Linux LLC                    */
+#define AF_TIPC                30      /* TIPC sockets                 */
 #define AF_BLUETOOTH   31      /* Bluetooth sockets            */
 #define AF_MAX         32      /* For now.. */
 
@@ -218,6 +219,7 @@ struct ucred {
 #define PF_PPPOX       AF_PPPOX
 #define PF_WANPIPE     AF_WANPIPE
 #define PF_LLC         AF_LLC
+#define PF_TIPC                AF_TIPC
 #define PF_BLUETOOTH   AF_BLUETOOTH
 #define PF_MAX         AF_MAX
 
@@ -279,6 +281,7 @@ struct ucred {
 #define SOL_LLC                268
 #define SOL_DCCP       269
 #define SOL_NETLINK    270
+#define SOL_TIPC       271
 
 /* IPX options */
 #define IPX_TYPE       1
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
new file mode 100644 (file)
index 0000000..72261e0
--- /dev/null
@@ -0,0 +1,18 @@
+/* linux/spi/ads7846.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 ads7846_platform_data {
+       u16     model;                  /* 7843, 7845, 7846. */
+       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;
+};
+
diff --git a/include/linux/spi/flash.h b/include/linux/spi/flash.h
new file mode 100644 (file)
index 0000000..3f22932
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef LINUX_SPI_FLASH_H
+#define LINUX_SPI_FLASH_H
+
+struct mtd_partition;
+
+/**
+ * struct flash_platform_data: board-specific flash data
+ * @name: optional flash device name (eg, as used with mtdparts=)
+ * @parts: optional array of mtd_partitions for static partitioning
+ * @nr_parts: number of mtd_partitions for static partitoning
+ * @type: optional flash device type (e.g. m25p80 vs m25p64), for use
+ *     with chips that can't be queried for JEDEC or other IDs
+ *
+ * Board init code (in arch/.../mach-xxx/board-yyy.c files) can
+ * provide information about SPI flash parts (such as DataFlash) to
+ * help set up the device and its appropriate default partitioning.
+ *
+ * Note that for DataFlash, sizes for pages, blocks, and sectors are
+ * rarely powers of two; and partitions should be sector-aligned.
+ */
+struct flash_platform_data {
+       char            *name;
+       struct mtd_partition *parts;
+       unsigned int    nr_parts;
+
+       char            *type;
+
+       /* we'll likely add more ... use JEDEC IDs, etc */
+};
+
+#endif
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
new file mode 100644 (file)
index 0000000..b05f146
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2005 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_SPI_H
+#define __LINUX_SPI_H
+
+/*
+ * INTERFACES between SPI master-side drivers and SPI infrastructure.
+ * (There's no SPI slave support for Linux yet...)
+ */
+extern struct bus_type spi_bus_type;
+
+/**
+ * struct spi_device - Master side proxy for an SPI slave device
+ * @dev: Driver model representation of the device.
+ * @master: SPI controller used with the device.
+ * @max_speed_hz: Maximum clock rate to be used with this chip
+ *     (on this board); may be changed by the device's driver.
+ * @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.
+ * @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).
+ *     This may be changed by the device's driver.
+ * @irq: Negative, or the number passed to request_irq() to receive
+ *     interrupts from this device.
+ * @controller_state: Controller's runtime state
+ * @controller_data: Board-specific definitions for controller, such as
+ *     FIFO initialization parameters; from board_info.controller_data
+ *
+ * An 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
+ * 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.
+ */
+struct spi_device {
+       struct device           dev;
+       struct spi_master       *master;
+       u32                     max_speed_hz;
+       u8                      chip_select;
+       u8                      mode;
+#define        SPI_CPHA        0x01                    /* clock phase */
+#define        SPI_CPOL        0x02                    /* clock polarity */
+#define        SPI_MODE_0      (0|0)                   /* (original MicroWire) */
+#define        SPI_MODE_1      (0|SPI_CPHA)
+#define        SPI_MODE_2      (SPI_CPOL|0)
+#define        SPI_MODE_3      (SPI_CPOL|SPI_CPHA)
+#define        SPI_CS_HIGH     0x04                    /* chipselect active high? */
+       u8                      bits_per_word;
+       int                     irq;
+       void                    *controller_state;
+       void                    *controller_data;
+       const char              *modalias;
+
+       // likely need more hooks for more protocol options affecting how
+       // the controller talks to each chip, like:
+       //  - bit order (default is wordwise msb-first)
+       //  - 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)
+{
+       return dev ? container_of(dev, struct spi_device, dev) : NULL;
+}
+
+/* most drivers won't need to care about device refcounting */
+static inline struct spi_device *spi_dev_get(struct spi_device *spi)
+{
+       return (spi && get_device(&spi->dev)) ? spi : NULL;
+}
+
+static inline void spi_dev_put(struct spi_device *spi)
+{
+       if (spi)
+               put_device(&spi->dev);
+}
+
+/* ctldata is for the bus_master driver's runtime state */
+static inline void *spi_get_ctldata(struct spi_device *spi)
+{
+       return spi->controller_state;
+}
+
+static inline void spi_set_ctldata(struct spi_device *spi, void *state)
+{
+       spi->controller_state = state;
+}
+
+
+struct spi_message;
+
+
+
+struct spi_driver {
+       int                     (*probe)(struct spi_device *spi);
+       int                     (*remove)(struct spi_device *spi);
+       void                    (*shutdown)(struct spi_device *spi);
+       int                     (*suspend)(struct spi_device *spi, pm_message_t mesg);
+       int                     (*resume)(struct spi_device *spi);
+       struct device_driver    driver;
+};
+
+static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
+{
+       return drv ? container_of(drv, struct spi_driver, driver) : NULL;
+}
+
+extern int spi_register_driver(struct spi_driver *sdrv);
+
+static inline void spi_unregister_driver(struct spi_driver *sdrv)
+{
+       if (!sdrv)
+               return;
+       driver_unregister(&sdrv->driver);
+}
+
+
+
+/**
+ * struct spi_master - interface to SPI master controller
+ * @cdev: class interface to this driver
+ * @bus_num: board-specific (and often SOC-specific) identifier for a
+ *     given SPI controller.
+ * @num_chipselect: chipselects are used to distinguish individual
+ *     SPI slaves, and are numbered from zero to num_chipselects.
+ *     each slave has a chipselect signal, but it's common that not
+ *     every chipselect is connected to a slave.
+ * @setup: updates the device mode and clocking records used by a
+ *     device's SPI controller; protocol code may call this.
+ * @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
+ * 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
+ * message's completion function when the transaction completes.
+ */
+struct spi_master {
+       struct class_device     cdev;
+
+       /* other than zero (== assign one dynamically), bus_num is fully
+        * board-specific.  usually that simplifies to being SOC-specific.
+        * example:  one SOC has three SPI controllers, numbered 1..3,
+        * and one board's schematics might show it using SPI-2.  software
+        * would normally use bus_num=2 for that controller.
+        */
+       u16                     bus_num;
+
+       /* chipselects will be integral to many controllers; some others
+        * might use board-specific GPIOs.
+        */
+       u16                     num_chipselect;
+
+       /* setup mode and clock, etc (spi driver may call many times) */
+       int                     (*setup)(struct spi_device *spi);
+
+       /* bidirectional bulk transfers
+        *
+        * + The transfer() method may not sleep; its main role is
+        *   just to add the message to the queue.
+        * + For now there's no remove-from-queue operation, or
+        *   any other request management
+        * + To a given spi_device, message queueing is pure fifo
+        *
+        * + The master's main job is to process its message queue,
+        *   selecting a chip then transferring data
+        * + If there are multiple spi_device children, the i/o queue
+        *   arbitration algorithm is unspecified (round robin, fifo,
+        *   priority, reservations, preemption, etc)
+        *
+        * + Chipselect stays active during the entire message
+        *   (unless modified by spi_transfer.cs_change != 0).
+        * + The message transfers use clock and SPI mode parameters
+        *   previously established by setup() for this device
+        */
+       int                     (*transfer)(struct spi_device *spi,
+                                               struct spi_message *mesg);
+
+       /* called on release() to free memory provided by spi_master */
+       void                    (*cleanup)(const struct spi_device *spi);
+};
+
+static inline void *spi_master_get_devdata(struct spi_master *master)
+{
+       return class_get_devdata(&master->cdev);
+}
+
+static inline void spi_master_set_devdata(struct spi_master *master, void *data)
+{
+       class_set_devdata(&master->cdev, data);
+}
+
+static inline struct spi_master *spi_master_get(struct spi_master *master)
+{
+       if (!master || !class_device_get(&master->cdev))
+               return NULL;
+       return master;
+}
+
+static inline void spi_master_put(struct spi_master *master)
+{
+       if (master)
+               class_device_put(&master->cdev);
+}
+
+
+/* the spi driver core manages memory for the spi_master classdev */
+extern struct spi_master *
+spi_alloc_master(struct device *host, unsigned size);
+
+extern int spi_register_master(struct spi_master *master);
+extern void spi_unregister_master(struct spi_master *master);
+
+extern struct spi_master *spi_busnum_to_master(u16 busnum);
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * I/O INTERFACE between SPI controller and protocol drivers
+ *
+ * Protocol drivers use a queue of spi_messages, each transferring data
+ * between the controller and memory buffers.
+ *
+ * The spi_messages themselves consist of a series of read+write transfer
+ * segments.  Those segments always read the same number of bits as they
+ * write; but one or the other is easily ignored by passing a null buffer
+ * pointer.  (This is unlike most types of I/O API, because SPI hardware
+ * is full duplex.)
+ *
+ * NOTE:  Allocation of spi_transfer and spi_message memory is entirely
+ * up to the protocol driver, which guarantees the integrity of both (as
+ * well as the data buffers) for as long as the message is queued.
+ */
+
+/**
+ * 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
+ * @len: size of rx and tx buffers (in bytes)
+ * @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
+ *
+ * SPI transfers always write the same number of bytes as they read.
+ * 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, undefined data will be shifted out
+ * 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;
+ * the former uses two bytes per word, the latter uses four bytes.)
+ *
+ * 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:
+ *
+ * (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
+ * message.  Toggling chipselect in this way may be needed to terminate
+ * a chip command, letting a single spi_message perform all of group of
+ * chip transactions together.
+ *
+ * (ii) When the transfer is the last one in the message, the chip may
+ * stay selected until the next transfer.  This is purely a performance
+ * hint; the controller driver may need to select a different device
+ * for the next message.
+ *
+ * The code that submits an spi_message (and its spi_transfers)
+ * to the lower layers is responsible for managing its memory.
+ * Zero-initialize every field you don't set up explicitly, to
+ * insulate against future API updates.  After you submit a message
+ * and its transfers, ignore them until its completion callback.
+ */
+struct spi_transfer {
+       /* it's ok if tx_buf == rx_buf (right?)
+        * for MicroWire, one buffer must be null
+        * buffers must work with dma_*map_single() calls, unless
+        *   spi_message.is_dma_mapped reports a pre-existing mapping
+        */
+       const void      *tx_buf;
+       void            *rx_buf;
+       unsigned        len;
+
+       dma_addr_t      tx_dma;
+       dma_addr_t      rx_dma;
+
+       unsigned        cs_change:1;
+       u16             delay_usecs;
+
+       struct list_head transfer_list;
+};
+
+/**
+ * struct spi_message - one multi-segment SPI transaction
+ * @transfers: list of transfer segments in this transaction
+ * @spi: SPI device to which the transaction is queued
+ * @is_dma_mapped: if true, the caller provided both dma and cpu virtual
+ *     addresses for each transfer buffer
+ * @complete: called to report transaction completions
+ * @context: the argument to complete() when it's called
+ * @actual_length: the total number of bytes that were transferred in all
+ *     successful segments
+ * @status: zero for success, else negative errno
+ * @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,
+ * 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
+ * as single programmed DMA transfer.  On all systems, these messages are
+ * queued, and might complete after transactions to other devices.  Messages
+ * sent to a given spi_device are alway executed in FIFO order.
+ *
+ * The code that submits an spi_message (and its spi_transfers)
+ * to the lower layers is responsible for managing its memory.
+ * Zero-initialize every field you don't set up explicitly, to
+ * insulate against future API updates.  After you submit a message
+ * and its transfers, ignore them until its completion callback.
+ */
+struct spi_message {
+       struct list_head        transfers;
+
+       struct spi_device       *spi;
+
+       unsigned                is_dma_mapped:1;
+
+       /* REVISIT:  we might want a flag affecting the behavior of the
+        * last transfer ... allowing things like "read 16 bit length L"
+        * immediately followed by "read L bytes".  Basically imposing
+        * a specific message scheduling algorithm.
+        *
+        * Some controller drivers (message-at-a-time queue processing)
+        * could provide that as their default scheduling algorithm.  But
+        * others (with multi-message pipelines) could need a flag to
+        * tell them about such special cases.
+        */
+
+       /* completion is reported through a callback */
+       void                    (*complete)(void *context);
+       void                    *context;
+       unsigned                actual_length;
+       int                     status;
+
+       /* for optional use by whatever driver currently owns the
+        * spi_message ...  between calls to spi_async and then later
+        * complete(), that's the spi_master controller driver.
+        */
+       struct list_head        queue;
+       void                    *state;
+};
+
+static inline void spi_message_init(struct spi_message *m)
+{
+       memset(m, 0, sizeof *m);
+       INIT_LIST_HEAD(&m->transfers);
+}
+
+static inline void
+spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
+{
+       list_add_tail(&t->transfer_list, &m->transfers);
+}
+
+static inline void
+spi_transfer_del(struct spi_transfer *t)
+{
+       list_del(&t->transfer_list);
+}
+
+/* It's fine to embed message and transaction structures in other data
+ * structures so long as you don't free them while they're in use.
+ */
+
+static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags)
+{
+       struct spi_message *m;
+
+       m = kzalloc(sizeof(struct spi_message)
+                       + ntrans * sizeof(struct spi_transfer),
+                       flags);
+       if (m) {
+               int i;
+               struct spi_transfer *t = (struct spi_transfer *)(m + 1);
+
+               INIT_LIST_HEAD(&m->transfers);
+               for (i = 0; i < ntrans; i++, t++)
+                       spi_message_add_tail(t, m);
+       }
+       return m;
+}
+
+static inline void spi_message_free(struct spi_message *m)
+{
+       kfree(m);
+}
+
+/**
+ * spi_setup -- setup SPI mode and clock rate
+ * @spi: the device whose settings are being modified
+ *
+ * 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
+ * to update clock rates or word sizes from initial values.  This function
+ * changes those settings, and must be called from a context that can sleep.
+ * The changes take effect the next time the device is selected and data
+ * is transferred to or from it.
+ */
+static inline int
+spi_setup(struct spi_device *spi)
+{
+       return spi->master->setup(spi);
+}
+
+
+/**
+ * spi_async -- asynchronous SPI transfer
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers, including completion callback
+ *
+ * This call may be used in_irq and other contexts which can't sleep,
+ * as well as from task contexts which can sleep.
+ *
+ * The completion callback is invoked in a context which can't sleep.
+ * Before that invocation, the value of message->status is undefined.
+ * When the callback is issued, message->status holds either zero (to
+ * indicate complete success) or a negative error code.  After that
+ * callback returns, the driver which issued the transfer request may
+ * deallocate the associated memory; it's no longer in use by any SPI
+ * core or controller driver code.
+ *
+ * Note that although all messages to a spi_device are handled in
+ * FIFO order, messages may go to different devices in other orders.
+ * Some device might be higher priority, or have various "hard" access
+ * time requirements, for example.
+ *
+ * On detection of any fault during the transfer, processing of
+ * the entire message is aborted, and the device is deselected.
+ * Until returning from the associated message completion callback,
+ * no other spi_message queued to that device will be processed.
+ * (This rule applies equally to all the synchronous transfer calls,
+ * which are wrappers around this core asynchronous primitive.)
+ */
+static inline int
+spi_async(struct spi_device *spi, struct spi_message *message)
+{
+       message->spi = spi;
+       return spi->master->transfer(spi, message);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* All these synchronous SPI transfer routines are utilities layered
+ * over the core async transfer primitive.  Here, "synchronous" means
+ * they will sleep uninterruptibly until the async transfer completes.
+ */
+
+extern int spi_sync(struct spi_device *spi, struct spi_message *message);
+
+/**
+ * spi_write - SPI synchronous write
+ * @spi: device to which data will be written
+ * @buf: data buffer
+ * @len: data buffer size
+ *
+ * This writes the buffer and returns zero or a negative error code.
+ * Callable only from contexts that can sleep.
+ */
+static inline int
+spi_write(struct spi_device *spi, const u8 *buf, size_t len)
+{
+       struct spi_transfer     t = {
+                       .tx_buf         = buf,
+                       .len            = len,
+               };
+       struct spi_message      m;
+
+       spi_message_init(&m);
+       spi_message_add_tail(&t, &m);
+       return spi_sync(spi, &m);
+}
+
+/**
+ * spi_read - SPI synchronous read
+ * @spi: device from which data will be read
+ * @buf: data buffer
+ * @len: data buffer size
+ *
+ * This writes the buffer and returns zero or a negative error code.
+ * Callable only from contexts that can sleep.
+ */
+static inline int
+spi_read(struct spi_device *spi, u8 *buf, size_t len)
+{
+       struct spi_transfer     t = {
+                       .rx_buf         = buf,
+                       .len            = len,
+               };
+       struct spi_message      m;
+
+       spi_message_init(&m);
+       spi_message_add_tail(&t, &m);
+       return spi_sync(spi, &m);
+}
+
+/* this copies txbuf and rxbuf data; for small transfers only! */
+extern int spi_write_then_read(struct spi_device *spi,
+               const u8 *txbuf, unsigned n_tx,
+               u8 *rxbuf, unsigned n_rx);
+
+/**
+ * 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
+ *
+ * This returns the (unsigned) eight bit number returned by the
+ * device, or else a negative error code.  Callable only from
+ * contexts that can sleep.
+ */
+static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
+{
+       ssize_t                 status;
+       u8                      result;
+
+       status = spi_write_then_read(spi, &cmd, 1, &result, 1);
+
+       /* return negative errno or unsigned value */
+       return (status < 0) ? status : result;
+}
+
+/**
+ * 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
+ *
+ * This returns the (unsigned) sixteen bit number returned by the
+ * device, or else a negative error code.  Callable only from
+ * contexts that can sleep.
+ *
+ * The number is returned in wire-order, which is at least sometimes
+ * big-endian.
+ */
+static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
+{
+       ssize_t                 status;
+       u16                     result;
+
+       status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);
+
+       /* return negative errno or unsigned value */
+       return (status < 0) ? status : result;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * INTERFACE between board init code and SPI infrastructure.
+ *
+ * No SPI driver ever sees these SPI device table segments, but
+ * it's how the SPI core (or adapters that get hotplugged) grows
+ * the driver model tree.
+ *
+ * As a rule, SPI devices can't be probed.  Instead, board init code
+ * provides a table listing the devices which are present, with enough
+ * information to bind and set up the device's driver.  There's basic
+ * support for nonstatic configurations too; enough to handle adding
+ * parport adapters, or microcontrollers acting as USB-to-SPI bridges.
+ */
+
+/* board-specific information about each SPI device */
+struct spi_board_info {
+       /* the device name and module name are coupled, like platform_bus;
+        * "modalias" is normally the driver name.
+        *
+        * platform_data goes to spi_device.dev.platform_data,
+        * controller_data goes to spi_device.controller_data,
+        * irq is copied too
+        */
+       char            modalias[KOBJ_NAME_LEN];
+       const void      *platform_data;
+       void            *controller_data;
+       int             irq;
+
+       /* slower signaling on noisy or low voltage boards */
+       u32             max_speed_hz;
+
+
+       /* bus_num is board specific and matches the bus_num of some
+        * spi_master that will probably be registered later.
+        *
+        * chip_select reflects how this chip is wired to that master;
+        * it's less than num_chipselect.
+        */
+       u16             bus_num;
+       u16             chip_select;
+
+       /* ... may need additional spi_device chip config data here.
+        * avoid stuff protocol drivers can set; but include stuff
+        * needed to behave without being bound to a driver:
+        *  - chipselect polarity
+        *  - quirks like clock rate mattering when not selected
+        */
+};
+
+#ifdef CONFIG_SPI
+extern int
+spi_register_board_info(struct spi_board_info const *info, unsigned n);
+#else
+/* board init code may ignore whether SPI is configured or not */
+static inline int
+spi_register_board_info(struct spi_board_info const *info, unsigned n)
+       { return 0; }
+#endif
+
+
+/* If you're hotplugging an adapter with devices (parport, usb, etc)
+ * use spi_new_device() to describe each device.  You can also call
+ * spi_unregister_device() to start making that device vanish, but
+ * normally that would be handled by spi_unregister_master().
+ */
+extern struct spi_device *
+spi_new_device(struct spi_master *, struct spi_board_info *);
+
+static inline void
+spi_unregister_device(struct spi_device *spi)
+{
+       if (spi)
+               device_unregister(&spi->dev);
+}
+
+#endif /* __LINUX_SPI_H */
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
new file mode 100644 (file)
index 0000000..c961fe9
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef        __SPI_BITBANG_H
+#define        __SPI_BITBANG_H
+
+/*
+ * Mix this utility code with some glue code to get one of several types of
+ * simple SPI master driver.  Two do polled word-at-a-time I/O:
+ *
+ *   - GPIO/parport bitbangers.  Provide chipselect() and txrx_word[](),
+ *     expanding the per-word routines from the inline templates below.
+ *
+ *   - Drivers for controllers resembling bare shift registers.  Provide
+ *     chipselect() and txrx_word[](), with custom setup()/cleanup() methods
+ *     that use your controller's clock and chipselect registers.
+ *
+ * Some hardware works well with requests at spi_transfer scope:
+ *
+ *   - Drivers leveraging smarter hardware, with fifos or DMA; or for half
+ *     duplex (MicroWire) controllers.  Provide chipslect() and txrx_bufs(),
+ *     and custom setup()/cleanup() methods.
+ */
+struct spi_bitbang {
+       struct workqueue_struct *workqueue;
+       struct work_struct      work;
+
+       spinlock_t              lock;
+       struct list_head        queue;
+       u8                      busy;
+       u8                      shutdown;
+       u8                      use_dma;
+
+       struct spi_master       *master;
+
+       void    (*chipselect)(struct spi_device *spi, int is_on);
+#define        BITBANG_CS_ACTIVE       1       /* normally nCS, active low */
+#define        BITBANG_CS_INACTIVE     0
+
+       /* txrx_bufs() may handle dma mapping for transfers that don't
+        * already have one (transfer.{tx,rx}_dma is zero), or use PIO
+        */
+       int     (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
+
+       /* txrx_word[SPI_MODE_*]() just looks like a shift register */
+       u32     (*txrx_word[4])(struct spi_device *spi,
+                       unsigned nsecs,
+                       u32 word, u8 bits);
+};
+
+/* you can call these default bitbang->master methods from your custom
+ * methods, if you like.
+ */
+extern int spi_bitbang_setup(struct spi_device *spi);
+extern void spi_bitbang_cleanup(const struct spi_device *spi);
+extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
+
+/* start or stop queue processing */
+extern int spi_bitbang_start(struct spi_bitbang *spi);
+extern int spi_bitbang_stop(struct spi_bitbang *spi);
+
+#endif /* __SPI_BITBANG_H */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef EXPAND_BITBANG_TXRX
+
+/*
+ * The code that knows what GPIO pins do what should have declared four
+ * functions, ideally as inlines, before #defining EXPAND_BITBANG_TXRX
+ * and including this header:
+ *
+ *  void setsck(struct spi_device *, int is_on);
+ *  void setmosi(struct spi_device *, int is_on);
+ *  int getmiso(struct spi_device *);
+ *  void spidelay(unsigned);
+ *
+ * A non-inlined routine would call bitbang_txrx_*() routines.  The
+ * main loop could easily compile down to a handful of instructions,
+ * especially if the delay is a NOP (to run at peak speed).
+ *
+ * Since this is software, the timings may not be exactly what your board's
+ * chips need ... there may be several reasons you'd need to tweak timings
+ * in these routines, not just make to make it faster or slower to match a
+ * particular CPU clock rate.
+ */
+
+static inline u32
+bitbang_txrx_be_cpha0(struct spi_device *spi,
+               unsigned nsecs, unsigned cpol,
+               u32 word, u8 bits)
+{
+       /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
+
+       /* clock starts at inactive polarity */
+       for (word <<= (32 - bits); likely(bits); bits--) {
+
+               /* setup MSB (to slave) on trailing edge */
+               setmosi(spi, word & (1 << 31));
+               spidelay(nsecs);        /* T(setup) */
+
+               setsck(spi, !cpol);
+               spidelay(nsecs);
+
+               /* sample MSB (from slave) on leading edge */
+               word <<= 1;
+               word |= getmiso(spi);
+               setsck(spi, cpol);
+       }
+       return word;
+}
+
+static inline u32
+bitbang_txrx_be_cpha1(struct spi_device *spi,
+               unsigned nsecs, unsigned cpol,
+               u32 word, u8 bits)
+{
+       /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
+
+       /* clock starts at inactive polarity */
+       for (word <<= (32 - bits); likely(bits); bits--) {
+
+               /* setup MSB (to slave) on leading edge */
+               setsck(spi, !cpol);
+               setmosi(spi, word & (1 << 31));
+               spidelay(nsecs); /* T(setup) */
+
+               setsck(spi, cpol);
+               spidelay(nsecs);
+
+               /* sample MSB (from slave) on trailing edge */
+               word <<= 1;
+               word |= getmiso(spi);
+       }
+       return word;
+}
+
+#endif /* EXPAND_BITBANG_TXRX */
index 389d1c382e208c2f05cabf86367624a9feb73b12..e92054d6530bd2d3ba770d35aa9f9a907ca3219e 100644 (file)
@@ -180,6 +180,11 @@ extern int isolate_lru_page(struct page *p);
 extern int putback_lru_pages(struct list_head *l);
 extern int migrate_pages(struct list_head *l, struct list_head *t,
                struct list_head *moved, struct list_head *failed);
+#else
+static inline int isolate_lru_page(struct page *p) { return -ENOSYS; }
+static inline int putback_lru_pages(struct list_head *l) { return 0; }
+static inline int migrate_pages(struct list_head *l, struct list_head *t,
+       struct list_head *moved, struct list_head *failed) { return -ENOSYS; }
 #endif
 
 #ifdef CONFIG_MMU
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
new file mode 100644 (file)
index 0000000..243a15f
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * include/linux/tipc.h: Include file for TIPC socket interface
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_TIPC_H_
+#define _LINUX_TIPC_H_
+
+#include <linux/types.h>
+
+/*
+ * TIPC addressing primitives
+ */
+struct tipc_portid {
+       __u32 ref;
+       __u32 node;
+};
+
+struct tipc_name {
+       __u32 type;
+       __u32 instance;
+};
+
+struct tipc_name_seq {
+       __u32 type;
+       __u32 lower;
+       __u32 upper;
+};
+
+static inline __u32 tipc_addr(unsigned int zone,
+                             unsigned int cluster,
+                             unsigned int node)
+{
+       return (zone << 24) | (cluster << 12) | node;
+}
+
+static inline unsigned int tipc_zone(__u32 addr)
+{
+       return addr >> 24;
+}
+
+static inline unsigned int tipc_cluster(__u32 addr)
+{
+       return (addr >> 12) & 0xfff;
+}
+
+static inline unsigned int tipc_node(__u32 addr)
+{
+       return addr & 0xfff;
+}
+
+/*
+ * Application-accessible port name types
+ */
+
+#define TIPC_CFG_SRV           0       /* configuration service name type */
+#define TIPC_TOP_SRV           1       /* topology service name type */
+#define TIPC_RESERVED_TYPES    64      /* lowest user-publishable name type */
+
+/* 
+ * Publication scopes when binding port names and port name sequences
+ */
+
+#define TIPC_ZONE_SCOPE                1
+#define TIPC_CLUSTER_SCOPE     2
+#define TIPC_NODE_SCOPE                3
+
+/*
+ * Limiting values for messages
+ */
+
+#define TIPC_MAX_USER_MSG_SIZE 66000
+
+/*
+ * Message importance levels
+ */
+
+#define TIPC_LOW_IMPORTANCE            0  /* default */
+#define TIPC_MEDIUM_IMPORTANCE         1
+#define TIPC_HIGH_IMPORTANCE           2
+#define TIPC_CRITICAL_IMPORTANCE       3
+
+/* 
+ * Msg rejection/connection shutdown reasons
+ */
+
+#define TIPC_OK                        0
+#define TIPC_ERR_NO_NAME       1
+#define TIPC_ERR_NO_PORT       2
+#define TIPC_ERR_NO_NODE       3
+#define TIPC_ERR_OVERLOAD      4
+#define TIPC_CONN_SHUTDOWN     5
+
+/*
+ * TIPC topology subscription service definitions
+ */
+
+#define TIPC_SUB_PORTS         0x01    /* filter for port availability */
+#define TIPC_SUB_SERVICE       0x02    /* filter for service availability */
+#if 0
+/* The following filter options are not currently implemented */
+#define TIPC_SUB_NO_BIND_EVTS  0x04    /* filter out "publish" events */
+#define TIPC_SUB_NO_UNBIND_EVTS        0x08    /* filter out "withdraw" events */
+#define TIPC_SUB_SINGLE_EVT    0x10    /* expire after first event */
+#endif
+
+#define TIPC_WAIT_FOREVER      ~0      /* timeout for permanent subscription */
+
+struct tipc_subscr {
+       struct tipc_name_seq seq;       /* name sequence of interest */
+       __u32 timeout;                  /* subscription duration (in ms) */
+        __u32 filter;                  /* bitmask of filter options */
+       char usr_handle[8];             /* available for subscriber use */
+};
+
+#define TIPC_PUBLISHED         1       /* publication event */
+#define TIPC_WITHDRAWN         2       /* withdraw event */
+#define TIPC_SUBSCR_TIMEOUT    3       /* subscription timeout event */
+
+struct tipc_event {
+       __u32 event;                    /* event type */
+       __u32 found_lower;              /* matching name seq instances */
+       __u32 found_upper;              /*    "      "    "     "      */
+       struct tipc_portid port;        /* associated port */
+       struct tipc_subscr s;           /* associated subscription */
+};
+
+/*
+ * Socket API
+ */
+
+#ifndef AF_TIPC
+#define AF_TIPC                30
+#endif
+
+#ifndef PF_TIPC
+#define PF_TIPC                AF_TIPC
+#endif
+
+#ifndef SOL_TIPC
+#define SOL_TIPC       271
+#endif
+
+#define TIPC_ADDR_NAMESEQ      1
+#define TIPC_ADDR_MCAST                1
+#define TIPC_ADDR_NAME         2
+#define TIPC_ADDR_ID           3
+
+struct sockaddr_tipc {
+       unsigned short family;
+       unsigned char  addrtype;
+       signed   char  scope;
+       union {
+               struct tipc_portid id;
+               struct tipc_name_seq nameseq;
+               struct {
+                       struct tipc_name name;
+                       __u32 domain; /* 0: own zone */
+               } name;
+       } addr;
+};
+
+/*
+ * Ancillary data objects supported by recvmsg()
+ */
+
+#define TIPC_ERRINFO   1       /* error info */
+#define TIPC_RETDATA   2       /* returned data */
+#define TIPC_DESTNAME  3       /* destination name */
+
+/*
+ * TIPC-specific socket option values
+ */
+
+#define TIPC_IMPORTANCE                127     /* Default: TIPC_LOW_IMPORTANCE */
+#define TIPC_SRC_DROPPABLE     128     /* Default: 0 (resend congested msg) */
+#define TIPC_DEST_DROPPABLE    129     /* Default: based on socket type */
+#define TIPC_CONN_TIMEOUT      130     /* Default: 8000 (ms)  */
+
+#endif
diff --git a/include/linux/tipc_config.h b/include/linux/tipc_config.h
new file mode 100644 (file)
index 0000000..a52c8c6
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * include/linux/tipc_config.h: Include file for TIPC configuration interface
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_TIPC_CONFIG_H_
+#define _LINUX_TIPC_CONFIG_H_
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+/*
+ * Configuration
+ *
+ * All configuration management messaging involves sending a request message
+ * to the TIPC configuration service on a node, which sends a reply message
+ * back.  (In the future multi-message replies may be supported.)
+ *
+ * Both request and reply messages consist of a transport header and payload.
+ * The transport header contains info about the desired operation;
+ * the payload consists of zero or more type/length/value (TLV) items
+ * which specify parameters or results for the operation.
+ *
+ * For many operations, the request and reply messages have a fixed number
+ * of TLVs (usually zero or one); however, some reply messages may return 
+ * a variable number of TLVs.  A failed request is denoted by the presence
+ * of an "error string" TLV in the reply message instead of the TLV(s) the
+ * reply should contain if the request succeeds.
+ */
+/* 
+ * Public commands:
+ * May be issued by any process.
+ * Accepted by own node, or by remote node only if remote management enabled.                       
+ */
+#define  TIPC_CMD_NOOP             0x0000    /* tx none, rx none */
+#define  TIPC_CMD_GET_NODES         0x0001    /* tx net_addr, rx node_info(s) */
+#define  TIPC_CMD_GET_MEDIA_NAMES   0x0002    /* tx none, rx media_name(s) */
+#define  TIPC_CMD_GET_BEARER_NAMES  0x0003    /* tx none, rx bearer_name(s) */
+#define  TIPC_CMD_GET_LINKS         0x0004    /* tx net_addr, rx link_info(s) */
+#define  TIPC_CMD_SHOW_NAME_TABLE   0x0005    /* tx name_tbl_query, rx ultra_string */
+#define  TIPC_CMD_SHOW_PORTS        0x0006    /* tx none, rx ultra_string */
+#define  TIPC_CMD_SHOW_LINK_STATS   0x000B    /* tx link_name, rx ultra_string */
+
+#if 0
+#define  TIPC_CMD_SHOW_PORT_STATS   0x0008    /* tx port_ref, rx ultra_string */
+#define  TIPC_CMD_RESET_PORT_STATS  0x0009    /* tx port_ref, rx none */
+#define  TIPC_CMD_GET_ROUTES        0x000A    /* tx ?, rx ? */
+#define  TIPC_CMD_GET_LINK_PEER     0x000D    /* tx link_name, rx ? */
+#endif
+
+/* 
+ * Protected commands:
+ * May only be issued by "network administration capable" process.
+ * Accepted by own node, or by remote node only if remote management enabled
+ * and this node is zone manager.                       
+ */
+
+#define  TIPC_CMD_GET_REMOTE_MNG    0x4003    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_PORTS     0x4004    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_PUBL      0x4005    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_SUBSCR    0x4006    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_ZONES     0x4007    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_CLUSTERS  0x4008    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_NODES     0x4009    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_MAX_SLAVES    0x400A    /* tx none, rx unsigned */
+#define  TIPC_CMD_GET_NETID         0x400B    /* tx none, rx unsigned */
+
+#define  TIPC_CMD_ENABLE_BEARER     0x4101    /* tx bearer_config, rx none */
+#define  TIPC_CMD_DISABLE_BEARER    0x4102    /* tx bearer_name, rx none */
+#define  TIPC_CMD_SET_LINK_TOL      0x4107    /* tx link_config, rx none */
+#define  TIPC_CMD_SET_LINK_PRI      0x4108    /* tx link_config, rx none */
+#define  TIPC_CMD_SET_LINK_WINDOW   0x4109    /* tx link_config, rx none */
+#define  TIPC_CMD_SET_LOG_SIZE      0x410A    /* tx unsigned, rx none */
+#define  TIPC_CMD_DUMP_LOG          0x410B    /* tx none, rx ultra_string */
+#define  TIPC_CMD_RESET_LINK_STATS  0x410C    /* tx link_name, rx none */
+
+#if 0
+#define  TIPC_CMD_CREATE_LINK       0x4103    /* tx link_create, rx none */
+#define  TIPC_CMD_REMOVE_LINK       0x4104    /* tx link_name, rx none */
+#define  TIPC_CMD_BLOCK_LINK        0x4105    /* tx link_name, rx none */
+#define  TIPC_CMD_UNBLOCK_LINK      0x4106    /* tx link_name, rx none */
+#endif
+
+/* 
+ * Private commands:
+ * May only be issued by "network administration capable" process.
+ * Accepted by own node only; cannot be used on a remote node.                       
+ */
+
+#define  TIPC_CMD_SET_NODE_ADDR     0x8001    /* tx net_addr, rx none */
+#if 0
+#define  TIPC_CMD_SET_ZONE_MASTER   0x8002    /* tx none, rx none */
+#endif
+#define  TIPC_CMD_SET_REMOTE_MNG    0x8003    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_PORTS     0x8004    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_PUBL      0x8005    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_SUBSCR    0x8006    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_ZONES     0x8007    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_CLUSTERS  0x8008    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_NODES     0x8009    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_MAX_SLAVES    0x800A    /* tx unsigned, rx none */
+#define  TIPC_CMD_SET_NETID         0x800B    /* tx unsigned, rx none */
+
+/*
+ * TLV types defined for TIPC
+ */
+
+#define TIPC_TLV_NONE          0       /* no TLV present */
+#define TIPC_TLV_VOID          1       /* empty TLV (0 data bytes)*/
+#define TIPC_TLV_UNSIGNED      2       /* 32-bit integer */
+#define TIPC_TLV_STRING                3       /* char[128] (max) */
+#define TIPC_TLV_LARGE_STRING  4       /* char[2048] (max) */
+#define TIPC_TLV_ULTRA_STRING  5       /* char[32768] (max) */
+
+#define TIPC_TLV_ERROR_STRING  16      /* char[128] containing "error code" */
+#define TIPC_TLV_NET_ADDR      17      /* 32-bit integer denoting <Z.C.N> */
+#define TIPC_TLV_MEDIA_NAME    18      /* char[TIPC_MAX_MEDIA_NAME] */
+#define TIPC_TLV_BEARER_NAME   19      /* char[TIPC_MAX_BEARER_NAME] */
+#define TIPC_TLV_LINK_NAME     20      /* char[TIPC_MAX_LINK_NAME] */
+#define TIPC_TLV_NODE_INFO     21      /* struct tipc_node_info */
+#define TIPC_TLV_LINK_INFO     22      /* struct tipc_link_info */
+#define TIPC_TLV_BEARER_CONFIG  23     /* struct tipc_bearer_config */
+#define TIPC_TLV_LINK_CONFIG    24     /* struct tipc_link_config */
+#define TIPC_TLV_NAME_TBL_QUERY        25      /* struct tipc_name_table_query */
+#define TIPC_TLV_PORT_REF      26      /* 32-bit port reference */
+
+/*
+ * Maximum sizes of TIPC bearer-related names (including terminating NUL)
+ */ 
+
+#define TIPC_MAX_MEDIA_NAME    16      /* format = media */
+#define TIPC_MAX_IF_NAME       16      /* format = interface */
+#define TIPC_MAX_BEARER_NAME   32      /* format = media:interface */
+#define TIPC_MAX_LINK_NAME     60      /* format = Z.C.N:interface-Z.C.N:interface */
+
+/*
+ * Link priority limits (range from 0 to # priorities - 1)
+ */
+
+#define TIPC_NUM_LINK_PRI 32
+
+/*
+ * Link tolerance limits (min, default, max), in ms
+ */
+
+#define TIPC_MIN_LINK_TOL 50
+#define TIPC_DEF_LINK_TOL 1500
+#define TIPC_MAX_LINK_TOL 30000
+
+/*
+ * Link window limits (min, default, max), in packets
+ */
+
+#define TIPC_MIN_LINK_WIN 16
+#define TIPC_DEF_LINK_WIN 50
+#define TIPC_MAX_LINK_WIN 150
+
+
+struct tipc_node_info {
+       __u32 addr;                     /* network address of node */
+       __u32 up;                       /* 0=down, 1= up */
+};
+
+struct tipc_link_info {
+       __u32 dest;                     /* network address of peer node */
+       __u32 up;                       /* 0=down, 1=up */
+       char str[TIPC_MAX_LINK_NAME];   /* link name */
+};
+
+struct tipc_bearer_config {
+       __u32 priority;                 /* Range [1,31]. Override per link  */
+       __u32 detect_scope;     
+       char name[TIPC_MAX_BEARER_NAME];
+};
+
+struct tipc_link_config {
+       __u32 value;
+       char name[TIPC_MAX_LINK_NAME];
+};
+
+#define TIPC_NTQ_ALLTYPES 0x80000000
+
+struct tipc_name_table_query {
+       __u32 depth;    /* 1:type, 2:+name info, 3:+port info, 4+:+debug info */
+       __u32 type;     /* {t,l,u} info ignored if high bit of "depth" is set */
+       __u32 lowbound; /* (i.e. displays all entries of name table) */
+       __u32 upbound;
+};
+
+/*
+ * The error string TLV is a null-terminated string describing the cause 
+ * of the request failure.  To simplify error processing (and to save space)
+ * the first character of the string can be a special error code character
+ * (lying by the range 0x80 to 0xFF) which represents a pre-defined reason.
+ */
+
+#define TIPC_CFG_TLV_ERROR      "\x80"  /* request contains incorrect TLV(s) */
+#define TIPC_CFG_NOT_NET_ADMIN  "\x81" /* must be network administrator */
+#define TIPC_CFG_NOT_ZONE_MSTR "\x82"  /* must be zone master */
+#define TIPC_CFG_NO_REMOTE     "\x83"  /* remote management not enabled */
+#define TIPC_CFG_NOT_SUPPORTED  "\x84" /* request is not supported by TIPC */
+#define TIPC_CFG_INVALID_VALUE  "\x85"  /* request has invalid argument value */
+
+#if 0
+/* prototypes TLV structures for proposed commands */
+struct tipc_link_create {
+       __u32   domain;
+       struct tipc_media_addr peer_addr;
+       char bearer_name[TIPC_MAX_BEARER_NAME];
+};
+
+struct tipc_route_info {
+       __u32 dest;
+       __u32 router;
+};
+#endif
+
+/*
+ * A TLV consists of a descriptor, followed by the TLV value.
+ * TLV descriptor fields are stored in network byte order; 
+ * TLV values must also be stored in network byte order (where applicable).
+ * TLV descriptors must be aligned to addresses which are multiple of 4,
+ * so up to 3 bytes of padding may exist at the end of the TLV value area.
+ * There must not be any padding between the TLV descriptor and its value.
+ */
+
+struct tlv_desc {
+       __u16 tlv_len;          /* TLV length (descriptor + value) */
+       __u16 tlv_type;         /* TLV identifier */
+};
+
+#define TLV_ALIGNTO 4
+
+#define TLV_ALIGN(datalen) (((datalen)+(TLV_ALIGNTO-1)) & ~(TLV_ALIGNTO-1))
+#define TLV_LENGTH(datalen) (sizeof(struct tlv_desc) + (datalen))
+#define TLV_SPACE(datalen) (TLV_ALIGN(TLV_LENGTH(datalen)))
+#define TLV_DATA(tlv) ((void *)((char *)(tlv) + TLV_LENGTH(0)))
+
+static inline int TLV_OK(const void *tlv, __u16 space)
+{
+       /*
+        * Would also like to check that "tlv" is a multiple of 4,
+        * but don't know how to do this in a portable way.
+        * - Tried doing (!(tlv & (TLV_ALIGNTO-1))), but GCC compiler
+        *   won't allow binary "&" with a pointer.
+        * - Tried casting "tlv" to integer type, but causes warning about size
+        *   mismatch when pointer is bigger than chosen type (int, long, ...).
+        */
+
+       return (space >= TLV_SPACE(0)) &&
+               (ntohs(((struct tlv_desc *)tlv)->tlv_len) <= space);
+}
+
+static inline int TLV_CHECK(const void *tlv, __u16 space, __u16 exp_type)
+{
+       return TLV_OK(tlv, space) && 
+               (ntohs(((struct tlv_desc *)tlv)->tlv_type) == exp_type);
+}
+
+static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len)
+{
+       struct tlv_desc *tlv_ptr;
+       int tlv_len;
+
+       tlv_len = TLV_LENGTH(len);
+       tlv_ptr = (struct tlv_desc *)tlv;
+       tlv_ptr->tlv_type = htons(type);
+       tlv_ptr->tlv_len  = htons(tlv_len);
+       if (len && data)
+               memcpy(TLV_DATA(tlv_ptr), data, tlv_len);
+       return TLV_SPACE(len);
+}
+
+/*
+ * A TLV list descriptor simplifies processing of messages 
+ * containing multiple TLVs.
+ */
+
+struct tlv_list_desc {
+       struct tlv_desc *tlv_ptr;       /* ptr to current TLV */
+       __u32 tlv_space;                /* # bytes from curr TLV to list end */
+};
+
+static inline void TLV_LIST_INIT(struct tlv_list_desc *list, 
+                                void *data, __u32 space)
+{
+       list->tlv_ptr = (struct tlv_desc *)data;
+       list->tlv_space = space;
+}
+            
+static inline int TLV_LIST_EMPTY(struct tlv_list_desc *list)
+{ 
+       return (list->tlv_space == 0);
+}
+
+static inline int TLV_LIST_CHECK(struct tlv_list_desc *list, __u16 exp_type)
+{
+       return TLV_CHECK(list->tlv_ptr, list->tlv_space, exp_type);
+}
+
+static inline void *TLV_LIST_DATA(struct tlv_list_desc *list)
+{
+       return TLV_DATA(list->tlv_ptr);
+}
+
+static inline void TLV_LIST_STEP(struct tlv_list_desc *list)
+{
+       __u16 tlv_space = TLV_ALIGN(ntohs(list->tlv_ptr->tlv_len));
+
+        list->tlv_ptr = (struct tlv_desc *)((char *)list->tlv_ptr + tlv_space);
+       list->tlv_space -= tlv_space;
+}
+
+/*
+ * Configuration messages exchanged via NETLINK_GENERIC use the following
+ * family id, name, version and command.
+ */
+#define TIPC_GENL_NAME         "TIPC"
+#define TIPC_GENL_VERSION      0x1
+#define TIPC_GENL_CMD          0x1
+
+/*
+ * TIPC specific header used in NETLINK_GENERIC requests.
+ */
+struct tipc_genlmsghdr {
+       __u32 dest;             /* Destination address */
+       __u16 cmd;              /* Command */
+       __u16 reserved;         /* Unused */
+};
+
+#define TIPC_GENL_HDRLEN       NLMSG_ALIGN(sizeof(struct tipc_genlmsghdr))
+
+/*
+ * Configuration messages exchanged via TIPC sockets use the TIPC configuration 
+ * message header, which is defined below.  This structure is analogous 
+ * to the Netlink message header, but fields are stored in network byte order 
+ * and no padding is permitted between the header and the message data 
+ * that follows.
+ */
+
+struct tipc_cfg_msg_hdr
+{
+       __u32 tcm_len;          /* Message length (including header) */
+       __u16 tcm_type;         /* Command type */
+       __u16 tcm_flags;        /* Additional flags */
+       char  tcm_reserved[8];  /* Unused */
+};
+
+#define TCM_F_REQUEST  0x1     /* Flag: Request message */
+#define TCM_F_MORE     0x2     /* Flag: Message to be continued */
+
+#define TCM_ALIGN(datalen)  (((datalen)+3) & ~3)
+#define TCM_LENGTH(datalen) (sizeof(struct tipc_cfg_msg_hdr) + datalen)
+#define TCM_SPACE(datalen)  (TCM_ALIGN(TCM_LENGTH(datalen)))
+#define TCM_DATA(tcm_hdr)   ((void *)((char *)(tcm_hdr) + TCM_LENGTH(0)))
+
+static inline int TCM_SET(void *msg, __u16 cmd, __u16 flags,
+                         void *data, __u16 data_len)
+{
+       struct tipc_cfg_msg_hdr *tcm_hdr;
+       int msg_len;
+
+       msg_len = TCM_LENGTH(data_len);
+       tcm_hdr = (struct tipc_cfg_msg_hdr *)msg;
+       tcm_hdr->tcm_len   = htonl(msg_len);
+       tcm_hdr->tcm_type  = htons(cmd);
+       tcm_hdr->tcm_flags = htons(flags);
+       if (data_len && data)
+               memcpy(TCM_DATA(msg), data, data_len);
+       return TCM_SPACE(data_len);
+}
+
+#endif
index c5b96b2b81554e452630774254c1a2ae4e9a9f34..805de50df00da8255f02edc3757e440654d16762 100644 (file)
@@ -22,7 +22,6 @@ struct genl_family
        char                    name[GENL_NAMSIZ];
        unsigned int            version;
        unsigned int            maxattr;
-       struct module *         owner;
        struct nlattr **        attrbuf;        /* private */
        struct list_head        ops_list;       /* private */
        struct list_head        family_list;    /* private */
index 25b081a730e60716fe6b010161f41ca9c3b7ae15..91684436af8e96dfa004f5d3510edf99b4aa9593 100644 (file)
@@ -37,7 +37,4 @@ struct nf_conntrack_ipv4 {
 struct sk_buff *
 nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
 
-/* call to create an explicit dependency on nf_conntrack_l3proto_ipv4. */
-extern void need_ip_conntrack(void);
-
 #endif /*_NF_CONNTRACK_IPV4_H*/
index 64b82b74a65089d3f66dbf8a98c563dacb5e0359..6d075ca16e6eb1cf7b1a7a9e111a39dda0f2e3fd 100644 (file)
@@ -221,9 +221,6 @@ extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
 extern struct nf_conntrack_helper *
 __nf_conntrack_helper_find_byname(const char *name);
 
-/* call to create an explicit dependency on nf_conntrack. */
-extern void need_nf_conntrack(void);
-
 extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
                                const struct nf_conntrack_tuple *orig);
 
index 14ce790e5c65c81163ede74f7b7a02cb18b43b06..530ef1f752836df846a49812982c4ba5635bd8ab 100644 (file)
@@ -111,7 +111,7 @@ struct nf_conntrack_tuple
 #ifdef __KERNEL__
 
 #define NF_CT_DUMP_TUPLE(tp)                                               \
-DEBUGP("tuple %p: %u %u %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu -> %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu\n",                                     \
+DEBUGP("tuple %p: %u %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n",           \
        (tp), (tp)->src.l3num, (tp)->dst.protonum,                          \
        NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
        NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
index 8f241216f46bdb23e29425b58b308bea5a6b5092..a553f39f6aee66ec66e56c920fa46569251911e3 100644 (file)
@@ -225,13 +225,13 @@ extern int sctp_debug_flag;
        if (sctp_debug_flag) { \
                if (saddr->sa.sa_family == AF_INET6) { \
                        printk(KERN_DEBUG \
-                              lead "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" trail, \
+                              lead NIP6_FMT trail, \
                               leadparm, \
                               NIP6(saddr->v6.sin6_addr), \
                               otherparms); \
                } else { \
                        printk(KERN_DEBUG \
-                              lead "%u.%u.%u.%u" trail, \
+                              lead NIPQUAD_FMT trail, \
                               leadparm, \
                               NIPQUAD(saddr->v4.sin_addr.s_addr), \
                               otherparms); \
diff --git a/include/net/tipc/tipc.h b/include/net/tipc/tipc.h
new file mode 100644 (file)
index 0000000..9566608
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * include/net/tipc/tipc.h: Main include file for TIPC users
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_H_
+#define _NET_TIPC_H_
+
+#ifdef __KERNEL__
+
+#include <linux/tipc.h>
+#include <linux/skbuff.h>
+
+/* 
+ * Native API
+ */
+
+/*
+ * TIPC operating mode routines
+ */
+
+u32 tipc_get_addr(void);
+
+#define TIPC_NOT_RUNNING  0
+#define TIPC_NODE_MODE    1
+#define TIPC_NET_MODE     2
+
+typedef void (*tipc_mode_event)(void *usr_handle, int mode, u32 addr);
+
+int tipc_attach(unsigned int *userref, tipc_mode_event, void *usr_handle);
+
+void tipc_detach(unsigned int userref);
+
+int tipc_get_mode(void);
+
+/*
+ * TIPC port manipulation routines
+ */
+
+typedef void (*tipc_msg_err_event) (void *usr_handle,
+                                   u32 portref,
+                                   struct sk_buff **buf,
+                                   unsigned char const *data,
+                                   unsigned int size,
+                                   int reason, 
+                                   struct tipc_portid const *attmpt_destid);
+
+typedef void (*tipc_named_msg_err_event) (void *usr_handle,
+                                         u32 portref,
+                                         struct sk_buff **buf,
+                                         unsigned char const *data,
+                                         unsigned int size,
+                                         int reason, 
+                                         struct tipc_name_seq const *attmpt_dest);
+
+typedef void (*tipc_conn_shutdown_event) (void *usr_handle,
+                                         u32 portref,
+                                         struct sk_buff **buf,
+                                         unsigned char const *data,
+                                         unsigned int size,
+                                         int reason);
+
+typedef void (*tipc_msg_event) (void *usr_handle,
+                               u32 portref,
+                               struct sk_buff **buf,
+                               unsigned char const *data,
+                               unsigned int size,
+                               unsigned int importance, 
+                               struct tipc_portid const *origin);
+
+typedef void (*tipc_named_msg_event) (void *usr_handle,
+                                     u32 portref,
+                                     struct sk_buff **buf,
+                                     unsigned char const *data,
+                                     unsigned int size,
+                                     unsigned int importance, 
+                                     struct tipc_portid const *orig,
+                                     struct tipc_name_seq const *dest);
+
+typedef void (*tipc_conn_msg_event) (void *usr_handle,
+                                    u32 portref,
+                                    struct sk_buff **buf,
+                                    unsigned char const *data,
+                                    unsigned int size);
+
+typedef void (*tipc_continue_event) (void *usr_handle, 
+                                    u32 portref);
+
+int tipc_createport(unsigned int tipc_user, 
+                   void *usr_handle, 
+                   unsigned int importance, 
+                   tipc_msg_err_event error_cb, 
+                   tipc_named_msg_err_event named_error_cb, 
+                   tipc_conn_shutdown_event conn_error_cb, 
+                   tipc_msg_event message_cb, 
+                   tipc_named_msg_event named_message_cb, 
+                   tipc_conn_msg_event conn_message_cb, 
+                   tipc_continue_event continue_event_cb,/* May be zero */
+                   u32 *portref);
+
+int tipc_deleteport(u32 portref);
+
+int tipc_ownidentity(u32 portref, struct tipc_portid *port);
+
+int tipc_portimportance(u32 portref, unsigned int *importance);
+int tipc_set_portimportance(u32 portref, unsigned int importance);
+
+int tipc_portunreliable(u32 portref, unsigned int *isunreliable);
+int tipc_set_portunreliable(u32 portref, unsigned int isunreliable);
+
+int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable);
+int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable);
+
+int tipc_publish(u32 portref, unsigned int scope, 
+                struct tipc_name_seq const *name_seq);
+int tipc_withdraw(u32 portref, unsigned int scope,
+                 struct tipc_name_seq const *name_seq); /* 0: all */
+
+int tipc_connect2port(u32 portref, struct tipc_portid const *port);
+
+int tipc_disconnect(u32 portref);
+
+int tipc_shutdown(u32 ref); /* Sends SHUTDOWN msg */
+
+int tipc_isconnected(u32 portref, int *isconnected);
+
+int tipc_peer(u32 portref, struct tipc_portid *peer);
+
+int tipc_ref_valid(u32 portref); 
+
+/*
+ * TIPC messaging routines
+ */
+
+#define TIPC_PORT_IMPORTANCE 100       /* send using current port setting */
+
+
+int tipc_send(u32 portref,
+             unsigned int num_sect,
+             struct iovec const *msg_sect);
+
+int tipc_send_buf(u32 portref,
+                 struct sk_buff *buf,
+                 unsigned int dsz);
+
+int tipc_send2name(u32 portref, 
+                  struct tipc_name const *name, 
+                  u32 domain,  /* 0:own zone */
+                  unsigned int num_sect,
+                  struct iovec const *msg_sect);
+
+int tipc_send_buf2name(u32 portref,
+                      struct tipc_name const *name,
+                      u32 domain,
+                      struct sk_buff *buf,
+                      unsigned int dsz);
+
+int tipc_forward2name(u32 portref, 
+                     struct tipc_name const *name, 
+                     u32 domain,   /*0: own zone */
+                     unsigned int section_count,
+                     struct iovec const *msg_sect,
+                     struct tipc_portid const *origin,
+                     unsigned int importance);
+
+int tipc_forward_buf2name(u32 portref,
+                         struct tipc_name const *name,
+                         u32 domain,
+                         struct sk_buff *buf,
+                         unsigned int dsz,
+                         struct tipc_portid const *orig,
+                         unsigned int importance);
+
+int tipc_send2port(u32 portref,
+                  struct tipc_portid const *dest,
+                  unsigned int num_sect,
+                  struct iovec const *msg_sect);
+
+int tipc_send_buf2port(u32 portref,
+                      struct tipc_portid const *dest,
+                      struct sk_buff *buf,
+                      unsigned int dsz);
+
+int tipc_forward2port(u32 portref,
+                     struct tipc_portid const *dest,
+                     unsigned int num_sect,
+                     struct iovec const *msg_sect,
+                     struct tipc_portid const *origin,
+                     unsigned int importance);
+
+int tipc_forward_buf2port(u32 portref,
+                         struct tipc_portid const *dest,
+                         struct sk_buff *buf,
+                         unsigned int dsz,
+                         struct tipc_portid const *orig,
+                         unsigned int importance);
+
+int tipc_multicast(u32 portref, 
+                  struct tipc_name_seq const *seq, 
+                  u32 domain,  /* 0:own zone */
+                  unsigned int section_count,
+                  struct iovec const *msg);
+
+#if 0
+int tipc_multicast_buf(u32 portref, 
+                      struct tipc_name_seq const *seq, 
+                      u32 domain,      /* 0:own zone */
+                      void *buf,
+                      unsigned int size);
+#endif
+
+/*
+ * TIPC subscription routines
+ */
+
+int tipc_ispublished(struct tipc_name const *name);
+
+/*
+ * Get number of available nodes within specified domain (excluding own node)
+ */
+
+unsigned int tipc_available_nodes(const u32 domain);
+
+#endif
+
+#endif
diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h
new file mode 100644 (file)
index 0000000..098607c
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * include/net/tipc/tipc_bearer.h: Include file for privileged access to TIPC bearers
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_BEARER_H_
+#define _NET_TIPC_BEARER_H_
+
+#ifdef __KERNEL__
+
+#include <linux/tipc_config.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+
+/*
+ * Identifiers of supported TIPC media types
+ */
+
+#define TIPC_MEDIA_TYPE_ETH    1
+
+struct tipc_media_addr {
+       __u32  type;
+       union {
+               __u8   eth_addr[6];     /* Ethernet bearer */ 
+#if 0
+               /* Prototypes for other possible bearer types */
+
+               struct {
+                       __u16 sin_family;
+                       __u16 sin_port;
+                       struct {
+                               __u32 s_addr;
+                       } sin_addr;
+                       char pad[4];
+               } addr_in;              /* IP-based bearer */
+               __u16  sock_descr;      /* generic socket bearer */
+#endif
+       } dev_addr;
+};
+
+/**
+ * struct tipc_bearer - TIPC bearer info available to privileged users
+ * @usr_handle: pointer to additional user-defined information about bearer
+ * @mtu: max packet size bearer can support
+ * @blocked: non-zero if bearer is blocked
+ * @lock: spinlock for controlling access to bearer
+ * @addr: media-specific address associated with bearer
+ * @name: bearer name (format = media:interface)
+ * 
+ * Note: TIPC initializes "name" and "lock" fields; user is responsible for
+ * initialization all other fields when a bearer is enabled.
+ */
+
+struct tipc_bearer {
+       void *usr_handle;
+       u32 mtu;
+       int blocked;
+       spinlock_t lock;
+       struct tipc_media_addr addr;
+       char name[TIPC_MAX_BEARER_NAME];
+};
+
+
+int  tipc_register_media(u32 media_type,
+                        char *media_name, 
+                        int (*enable)(struct tipc_bearer *), 
+                        void (*disable)(struct tipc_bearer *), 
+                        int (*send_msg)(struct sk_buff *, 
+                                        struct tipc_bearer *,
+                                        struct tipc_media_addr *), 
+                        char *(*addr2str)(struct tipc_media_addr *a,
+                                          char *str_buf,
+                                          int str_size),
+                        struct tipc_media_addr *bcast_addr,
+                        const u32 bearer_priority,
+                        const u32 link_tolerance,  /* [ms] */
+                        const u32 send_window_limit); 
+
+void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr);
+
+int  tipc_block_bearer(const char *name);
+void tipc_continue(struct tipc_bearer *tb_ptr); 
+
+int tipc_enable_bearer(const char *bearer_name, u32 bcast_scope, u32 priority);
+int tipc_disable_bearer(const char *name);
+
+
+#endif
+
+#endif
diff --git a/include/net/tipc/tipc_msg.h b/include/net/tipc/tipc_msg.h
new file mode 100644 (file)
index 0000000..4d096ee
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * include/net/tipc/tipc_msg.h: Include file for privileged access to TIPC message headers
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_MSG_H_
+#define _NET_TIPC_MSG_H_
+
+#ifdef __KERNEL__
+
+struct tipc_msg {
+       u32 hdr[15];
+};
+
+
+/*
+               TIPC user data message header format, version 2:
+
+
+       1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w0:|vers | user  |hdr sz |n|d|s|-|          message size           |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w1:|mstyp| error |rer cnt|lsc|opt p|      broadcast ack no         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w2:|        link level ack no      |   broadcast/link level seq no |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w3:|                       previous node                           |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w4:|                      originating port                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w5:|                      destination port                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
+   w6:|                      originating node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w7:|                      destination node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w8:|            name type / transport sequence number              |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w9:|              name instance/multicast lower bound              |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
+   wA:|                    multicast upper bound                      |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    
+      /                                                               /
+      \                           options                             \
+      /                                                               /
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+*/
+
+#define TIPC_CONN_MSG  0
+#define TIPC_MCAST_MSG 1
+#define TIPC_NAMED_MSG 2
+#define TIPC_DIRECT_MSG        3
+
+
+static inline u32 msg_word(struct tipc_msg *m, u32 pos)
+{
+       return ntohl(m->hdr[pos]);
+}
+
+static inline u32 msg_bits(struct tipc_msg *m, u32 w, u32 pos, u32 mask)
+{
+       return (msg_word(m, w) >> pos) & mask;
+}
+
+static inline u32 msg_importance(struct tipc_msg *m)
+{
+       return msg_bits(m, 0, 25, 0xf);
+}
+
+static inline u32 msg_hdr_sz(struct tipc_msg *m)
+{
+       return msg_bits(m, 0, 21, 0xf) << 2;
+}
+
+static inline int msg_short(struct tipc_msg *m)
+{
+       return (msg_hdr_sz(m) == 24);
+}
+
+static inline u32 msg_size(struct tipc_msg *m)
+{
+       return msg_bits(m, 0, 0, 0x1ffff);
+}
+
+static inline u32 msg_data_sz(struct tipc_msg *m)
+{
+       return (msg_size(m) - msg_hdr_sz(m));
+}
+
+static inline unchar *msg_data(struct tipc_msg *m)
+{
+       return ((unchar *)m) + msg_hdr_sz(m);
+}
+
+static inline u32 msg_type(struct tipc_msg *m)
+{
+       return msg_bits(m, 1, 29, 0x7);
+}
+
+static inline u32 msg_direct(struct tipc_msg *m)
+{
+       return (msg_type(m) == TIPC_DIRECT_MSG);
+}
+
+static inline u32 msg_named(struct tipc_msg *m)
+{
+       return (msg_type(m) == TIPC_NAMED_MSG);
+}
+
+static inline u32 msg_mcast(struct tipc_msg *m)
+{
+       return (msg_type(m) == TIPC_MCAST_MSG);
+}
+
+static inline u32 msg_connected(struct tipc_msg *m)
+{
+       return (msg_type(m) == TIPC_CONN_MSG);
+}
+
+static inline u32 msg_errcode(struct tipc_msg *m)
+{
+       return msg_bits(m, 1, 25, 0xf);
+}
+
+static inline u32 msg_prevnode(struct tipc_msg *m)
+{
+       return msg_word(m, 3);
+}
+
+static inline u32 msg_origport(struct tipc_msg *m)
+{
+       return msg_word(m, 4);
+}
+
+static inline u32 msg_destport(struct tipc_msg *m)
+{
+       return msg_word(m, 5);
+}
+
+static inline u32 msg_mc_netid(struct tipc_msg *m)
+{
+       return msg_word(m, 5);
+}
+
+static inline u32 msg_orignode(struct tipc_msg *m)
+{
+       if (likely(msg_short(m)))
+               return msg_prevnode(m);
+       return msg_word(m, 6);
+}
+
+static inline u32 msg_destnode(struct tipc_msg *m)
+{
+       return msg_word(m, 7);
+}
+
+static inline u32 msg_nametype(struct tipc_msg *m)
+{
+       return msg_word(m, 8);
+}
+
+static inline u32 msg_nameinst(struct tipc_msg *m)
+{
+       return msg_word(m, 9);
+}
+
+static inline u32 msg_namelower(struct tipc_msg *m)
+{
+       return msg_nameinst(m);
+}
+
+static inline u32 msg_nameupper(struct tipc_msg *m)
+{
+       return msg_word(m, 10);
+}
+
+static inline char *msg_options(struct tipc_msg *m, u32 *len)
+{
+       u32 pos = msg_bits(m, 1, 16, 0x7);
+
+       if (!pos)
+               return 0;
+       pos = (pos * 4) + 28;
+       *len = msg_hdr_sz(m) - pos;
+       return (char *)&m->hdr[pos/4];
+}
+
+#endif
+
+#endif
diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h
new file mode 100644 (file)
index 0000000..333bba6
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * include/net/tipc/tipc_port.h: Include file for privileged access to TIPC ports
+ * 
+ * Copyright (c) 1994-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_TIPC_PORT_H_
+#define _NET_TIPC_PORT_H_
+
+#ifdef __KERNEL__
+
+#include <linux/tipc.h>
+#include <linux/skbuff.h>
+#include <net/tipc/tipc_msg.h>
+
+#define TIPC_FLOW_CONTROL_WIN 512
+
+/**
+ * struct tipc_port - native TIPC port info available to privileged users
+ * @usr_handle: pointer to additional user-defined information about port
+ * @lock: pointer to spinlock for controlling access to port
+ * @connected: non-zero if port is currently connected to a peer port
+ * @conn_type: TIPC type used when connection was established
+ * @conn_instance: TIPC instance used when connection was established
+ * @conn_unacked: number of unacknowledged messages received from peer port
+ * @published: non-zero if port has one or more associated names
+ * @congested: non-zero if cannot send because of link or port congestion
+ * @ref: unique reference to port in TIPC object registry
+ * @phdr: preformatted message header used when sending messages
+ */
+
+struct tipc_port {
+        void *usr_handle;
+        spinlock_t *lock;
+       int connected;
+        u32 conn_type;
+        u32 conn_instance;
+       u32 conn_unacked;
+       int published;
+       u32 congested;
+       u32 ref;
+       struct tipc_msg phdr;
+};
+
+
+/**
+ * tipc_createport_raw - create a native TIPC port and return it's reference
+ *
+ * Note: 'dispatcher' and 'wakeup' deliver a locked port.
+ */
+
+u32 tipc_createport_raw(void *usr_handle,
+                       u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
+                       void (*wakeup)(struct tipc_port *),
+                       const u32 importance);
+
+/*
+ * tipc_set_msg_option(): port must be locked.
+ */
+int tipc_set_msg_option(struct tipc_port *tp_ptr,
+                       const char *opt,
+                       const u32 len);
+
+int tipc_reject_msg(struct sk_buff *buf, u32 err);
+
+int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode);
+
+void tipc_acknowledge(u32 port_ref,u32 ack);
+
+struct tipc_port *tipc_get_port(const u32 ref);
+
+void *tipc_get_handle(const u32 ref);
+
+
+#endif
+
+#endif
+
index a7f4c355a91f76f0fbb8b41cc4edc0edb7b3d7e6..22fc886b9695f94fdca32e4d57b36a2391de7bc4 100644 (file)
@@ -88,7 +88,6 @@ enum ib_atomic_cap {
 
 struct ib_device_attr {
        u64                     fw_ver;
-       __be64                  node_guid;
        __be64                  sys_image_guid;
        u64                     max_mr_size;
        u64                     page_size_cap;
@@ -951,6 +950,7 @@ struct ib_device {
        u64                          uverbs_cmd_mask;
        int                          uverbs_abi_ver;
 
+       __be64                       node_guid;
        u8                           node_type;
        u8                           phys_port_cnt;
 };
index be1bc792ab181f83c95536505e87468c7604777a..3e5cb5ab2d34c54cd997f672190907a3e38bdd41 100644 (file)
@@ -168,6 +168,12 @@ typedef uint64_t iscsi_connh_t;            /* iSCSI Data-Path connection handle */
 
 #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
 #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
+#define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata))
+
+/**
+ * iscsi_hostdata - get LLD hostdata from scsi_host
+ * @_hostdata: pointer to scsi host's hostdata
+ **/
 #define iscsi_hostdata(_hostdata) ((void*)_hostdata + sizeof(unsigned long))
 
 /*
index 6cb1e2788d8bbeb701a5af243d19e622795087a4..c60b8ff2f5e4f5d7a2952a8fb0951a689ec451b1 100644 (file)
@@ -31,6 +31,12 @@ extern const unsigned char scsi_command_size[8];
 #define MAX_SCSI_DEVICE_CODE 15
 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 
+/*
+ * Special value for scanning to specify scanning or rescanning of all
+ * possible channels, (target) ids, or luns on a given shost.
+ */
+#define SCAN_WILD_CARD ~0
+
 /*
  *      SCSI opcodes
  */
index 41cfc29be8993562e3d265d5a38d02e3d9b576f1..7529f4388bb46df6655e61364217c78e2199ea18 100644 (file)
@@ -151,6 +151,5 @@ extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t);
 extern void scsi_put_command(struct scsi_cmnd *);
 extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int);
 extern void scsi_finish_command(struct scsi_cmnd *cmd);
-extern void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd);
 
 #endif /* _SCSI_SCSI_CMND_H */
index 230bc55c0bfa163be4c47437aa8ba82f6bb7e476..467274a764d172487c2717f0aa7eac2eb5f81b0d 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <linux/mutex.h>
 
 struct block_device;
 struct completion;
@@ -469,7 +470,7 @@ struct Scsi_Host {
        spinlock_t              default_lock;
        spinlock_t              *host_lock;
 
-       struct semaphore        scan_mutex;/* serialize scanning activity */
+       struct mutex            scan_mutex;/* serialize scanning activity */
 
        struct list_head        eh_cmd_q;
        struct task_struct    * ehandler;  /* Error recovery thread. */
index f6e0bb484c63efb9194c8be4ce90bc7b5da0d482..e7b1054adf86b5d3d1003f3be9335d9c158ae18b 100644 (file)
@@ -30,12 +30,9 @@ struct scsi_transport_template {
        struct transport_container device_attrs;
 
        /*
-        * If set, call target_parent prior to allocating a scsi_target,
-        * so we get the appropriate parent for the target. This function
-        * is required for transports like FC and iSCSI that do not put the
-        * scsi_target under scsi_host.
+        * If set, called from sysfs and legacy procfs rescanning code.
         */
-       struct device *(*target_parent)(struct Scsi_Host *, int, uint);
+       int (*user_scan)(struct Scsi_Host *, uint, uint, uint);
 
        /* The size of the specific transport attribute structure (a
         * space of this size will be left at the end of the
index 394f14a5b7cb44cc17ed888f865b358200eddaac..cf3fec8be1e358c6f3a95cef7d5eff5cf2dbc655 100644 (file)
@@ -303,6 +303,7 @@ struct fc_host_attrs {
        /* Fixed Attributes */
        u64 node_name;
        u64 port_name;
+       u64 permanent_port_name;
        u32 supported_classes;
        u8  supported_fc4s[FC_FC4_LIST_SIZE];
        char symbolic_name[FC_SYMBOLIC_NAME_SIZE];
@@ -338,6 +339,8 @@ struct fc_host_attrs {
        (((struct fc_host_attrs *)(x)->shost_data)->node_name)
 #define fc_host_port_name(x)   \
        (((struct fc_host_attrs *)(x)->shost_data)->port_name)
+#define fc_host_permanent_port_name(x) \
+       (((struct fc_host_attrs *)(x)->shost_data)->permanent_port_name)
 #define fc_host_supported_classes(x)   \
        (((struct fc_host_attrs *)(x)->shost_data)->supported_classes)
 #define fc_host_supported_fc4s(x)      \
@@ -426,6 +429,7 @@ struct fc_function_template {
        /* host fixed attributes */
        unsigned long   show_host_node_name:1;
        unsigned long   show_host_port_name:1;
+       unsigned long   show_host_permanent_port_name:1;
        unsigned long   show_host_supported_classes:1;
        unsigned long   show_host_supported_fc4s:1;
        unsigned long   show_host_symbolic_name:1;
index f25041c386ec26481d9814821118446848d6e252..16602a547a630a0d1ffd9e7e95b3b45e9288ae19 100644 (file)
 #ifndef SCSI_TRANSPORT_ISCSI_H
 #define SCSI_TRANSPORT_ISCSI_H
 
+#include <linux/device.h>
 #include <scsi/iscsi_if.h>
 
+struct scsi_transport_template;
+struct Scsi_Host;
+struct mempool_zone;
+struct iscsi_cls_conn;
+
 /**
  * struct iscsi_transport - iSCSI Transport template
  *
@@ -48,23 +54,31 @@ struct iscsi_transport {
        char *name;
        unsigned int caps;
        struct scsi_host_template *host_template;
+       /* LLD session/scsi_host data size */
        int hostdata_size;
+       /* LLD iscsi_host data size */
+       int ihostdata_size;
+       /* LLD connection data size */
+       int conndata_size;
        int max_lun;
        unsigned int max_conn;
        unsigned int max_cmd_len;
-       iscsi_sessionh_t (*create_session) (uint32_t initial_cmdsn,
-                                           struct Scsi_Host *shost);
-       void (*destroy_session) (iscsi_sessionh_t session);
-       iscsi_connh_t (*create_conn) (iscsi_sessionh_t session, uint32_t cid);
+       struct Scsi_Host *(*create_session) (struct scsi_transport_template *t,
+                                            uint32_t initial_cmdsn);
+       void (*destroy_session) (struct Scsi_Host *shost);
+       struct iscsi_cls_conn *(*create_conn) (struct Scsi_Host *shost,
+                               uint32_t cid);
        int (*bind_conn) (iscsi_sessionh_t session, iscsi_connh_t conn,
                          uint32_t transport_fd, int is_leading);
        int (*start_conn) (iscsi_connh_t conn);
        void (*stop_conn) (iscsi_connh_t conn, int flag);
-       void (*destroy_conn) (iscsi_connh_t conn);
+       void (*destroy_conn) (struct iscsi_cls_conn *conn);
        int (*set_param) (iscsi_connh_t conn, enum iscsi_param param,
                          uint32_t value);
-       int (*get_param) (iscsi_connh_t conn, enum iscsi_param param,
-                         uint32_t *value);
+       int (*get_conn_param) (void *conndata, enum iscsi_param param,
+                              uint32_t *value);
+       int (*get_session_param) (struct Scsi_Host *shost,
+                                 enum iscsi_param param, uint32_t *value);
        int (*send_pdu) (iscsi_connh_t conn, struct iscsi_hdr *hdr,
                         char *data, uint32_t data_size);
        void (*get_stats) (iscsi_connh_t conn, struct iscsi_stats *stats);
@@ -73,7 +87,7 @@ struct iscsi_transport {
 /*
  * transport registration upcalls
  */
-extern int iscsi_register_transport(struct iscsi_transport *tt);
+extern struct scsi_transport_template *iscsi_register_transport(struct iscsi_transport *tt);
 extern int iscsi_unregister_transport(struct iscsi_transport *tt);
 
 /*
@@ -83,4 +97,49 @@ extern void iscsi_conn_error(iscsi_connh_t conn, enum iscsi_err error);
 extern int iscsi_recv_pdu(iscsi_connh_t conn, struct iscsi_hdr *hdr,
                          char *data, uint32_t data_size);
 
+struct iscsi_cls_conn {
+       struct list_head conn_list;     /* item in connlist */
+       void *dd_data;                  /* LLD private data */
+       struct iscsi_transport *transport;
+       iscsi_connh_t connh;
+       int active;                     /* must be accessed with the connlock */
+       struct device dev;              /* sysfs transport/container device */
+       struct mempool_zone *z_error;
+       struct mempool_zone *z_pdu;
+       struct list_head freequeue;
+};
+
+#define iscsi_dev_to_conn(_dev) \
+       container_of(_dev, struct iscsi_cls_conn, dev)
+
+struct iscsi_cls_session {
+       struct list_head list;  /* item in session_list */
+       struct iscsi_transport *transport;
+       struct device dev;      /* sysfs transport/container device */
+};
+
+#define iscsi_dev_to_session(_dev) \
+       container_of(_dev, struct iscsi_cls_session, dev)
+
+#define iscsi_session_to_shost(_session) \
+       dev_to_shost(_session->dev.parent)
+
+/*
+ * session and connection functions that can be used by HW iSCSI LLDs
+ */
+extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost,
+                               struct iscsi_transport *t);
+extern int iscsi_destroy_session(struct iscsi_cls_session *session);
+extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess,
+                                           uint32_t cid);
+extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn);
+
+/*
+ * session functions used by software iscsi
+ */
+extern struct Scsi_Host *
+iscsi_transport_create_session(struct scsi_transport_template *scsit,
+                               struct iscsi_transport *transport);
+extern int iscsi_transport_destroy_session(struct Scsi_Host *shost);
+
 #endif
index 54a89611e9c5abc04f89013112c9ff9202dece6f..2b5930ba69ec465b43947e9e47493530448bb871 100644 (file)
@@ -54,7 +54,7 @@ struct spi_transport_attrs {
        unsigned int support_qas; /* supports quick arbitration and selection */
        /* Private Fields */
        unsigned int dv_pending:1; /* Internal flag */
-       struct semaphore dv_sem; /* semaphore to serialise dv */
+       struct mutex dv_mutex; /* semaphore to serialise dv */
 };
 
 enum spi_signal_type {
index e092b1979a9052022d20696c42a2ee22698738ae..7c79da57d3a29fd665042e5747e88bca78409aca 100644 (file)
 #include <asm/sections.h>
 #include <asm/cacheflush.h>
 
-/*
- * This is one of the first .c files built. Error out early
- * if we have compiler trouble..
- */
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
 
 /*
- * Versions of gcc older than that listed below may actually compile
- * and link okay, but the end product can have subtle run time bugs.
- * To avoid associated bogus bug reports, we flatly refuse to compile
- * with a gcc that is known to be too old from the very beginning.
+ * This is one of the first .c files built. Error out early if we have compiler
+ * trouble.
+ *
+ * Versions of gcc older than that listed below may actually compile and link
+ * okay, but the end product can have subtle run time bugs.  To avoid associated
+ * bogus bug reports, we flatly refuse to compile with a gcc that is known to be
+ * too old from the very beginning.
  */
 #if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2)
 #error Sorry, your GCC is too old. It builds incorrect kernels.
index 4e776f9c80e7c1fbe0da01a1dcdc9f63c04ebd89..59302fc3643b9243889946661249ab31d5f66d6f 100644 (file)
@@ -599,15 +599,16 @@ static int mq_attr_ok(struct mq_attr *attr)
 static struct file *do_create(struct dentry *dir, struct dentry *dentry,
                        int oflag, mode_t mode, struct mq_attr __user *u_attr)
 {
-       struct file *filp;
        struct mq_attr attr;
        int ret;
 
-       if (u_attr != NULL) {
+       if (u_attr) {
+               ret = -EFAULT;
                if (copy_from_user(&attr, u_attr, sizeof(attr)))
-                       return ERR_PTR(-EFAULT);
+                       goto out;
+               ret = -EINVAL;
                if (!mq_attr_ok(&attr))
-                       return ERR_PTR(-EINVAL);
+                       goto out;
                /* store for use during create */
                dentry->d_fsdata = &attr;
        }
@@ -616,13 +617,14 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry,
        ret = vfs_create(dir->d_inode, dentry, mode, NULL);
        dentry->d_fsdata = NULL;
        if (ret)
-               return ERR_PTR(ret);
+               goto out;
 
-       filp = dentry_open(dentry, mqueue_mnt, oflag);
-       if (!IS_ERR(filp))
-               dget(dentry);
+       return dentry_open(dentry, mqueue_mnt, oflag);
 
-       return filp;
+out:
+       dput(dentry);
+       mntput(mqueue_mnt);
+       return ERR_PTR(ret);
 }
 
 /* Opens existing queue */
@@ -630,20 +632,20 @@ static struct file *do_open(struct dentry *dentry, int oflag)
 {
 static int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
                                        MAY_READ | MAY_WRITE };
-       struct file *filp;
 
-       if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
+       if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
+               dput(dentry);
+               mntput(mqueue_mnt);
                return ERR_PTR(-EINVAL);
+       }
 
-       if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL))
+       if (permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE], NULL)) {
+               dput(dentry);
+               mntput(mqueue_mnt);
                return ERR_PTR(-EACCES);
+       }
 
-       filp = dentry_open(dentry, mqueue_mnt, oflag);
-
-       if (!IS_ERR(filp))
-               dget(dentry);
-
-       return filp;
+       return dentry_open(dentry, mqueue_mnt, oflag);
 }
 
 asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
@@ -671,17 +673,20 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
 
        if (oflag & O_CREAT) {
                if (dentry->d_inode) {  /* entry already exists */
-                       filp = (oflag & O_EXCL) ? ERR_PTR(-EEXIST) :
-                                       do_open(dentry, oflag);
+                       error = -EEXIST;
+                       if (oflag & O_EXCL)
+                               goto out;
+                       filp = do_open(dentry, oflag);
                } else {
                        filp = do_create(mqueue_mnt->mnt_root, dentry,
                                                oflag, mode, u_attr);
                }
-       } else
-               filp = (dentry->d_inode) ? do_open(dentry, oflag) :
-                                       ERR_PTR(-ENOENT);
-
-       dput(dentry);
+       } else {
+               error = -ENOENT;
+               if (!dentry->d_inode)
+                       goto out;
+               filp = do_open(dentry, oflag);
+       }
 
        if (IS_ERR(filp)) {
                error = PTR_ERR(filp);
@@ -692,8 +697,10 @@ asmlinkage long sys_mq_open(const char __user *u_name, int oflag, mode_t mode,
        fd_install(fd, filp);
        goto out_upsem;
 
-out_putfd:
+out:
+       dput(dentry);
        mntput(mqueue_mnt);
+out_putfd:
        put_unused_fd(fd);
 out_err:
        fd = error;
index 2a75e44e1a41355bc55cc4819f167e4bc63f0cab..fe2f71f92ae0b01fbbfe08053bb34e36058e85de 100644 (file)
@@ -1554,7 +1554,7 @@ struct ctr_struct {
  * when reading out p->cpuset, as we don't really care if it changes
  * on the next cycle, and we are not going to try to dereference it.
  */
-static inline int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs)
+static int pid_array_load(pid_t *pidarray, int npids, struct cpuset *cs)
 {
        int n = 0;
        struct task_struct *g, *p;
@@ -2149,6 +2149,33 @@ int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
        return allowed;
 }
 
+/**
+ * cpuset_lock - lock out any changes to cpuset structures
+ *
+ * The out of memory (oom) code needs to lock down cpusets
+ * from being changed while it scans the tasklist looking for a
+ * task in an overlapping cpuset.  Expose callback_sem via this
+ * cpuset_lock() routine, so the oom code can lock it, before
+ * locking the task list.  The tasklist_lock is a spinlock, so
+ * must be taken inside callback_sem.
+ */
+
+void cpuset_lock(void)
+{
+       down(&callback_sem);
+}
+
+/**
+ * cpuset_unlock - release lock on cpuset changes
+ *
+ * Undo the lock taken in a previous cpuset_lock() call.
+ */
+
+void cpuset_unlock(void)
+{
+       up(&callback_sem);
+}
+
 /**
  * cpuset_excl_nodes_overlap - Do we overlap @p's mem_exclusive ancestors?
  * @p: pointer to task_struct of some other task.
@@ -2158,7 +2185,7 @@ int __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
  * determine if task @p's memory usage might impact the memory
  * available to the current task.
  *
- * Acquires callback_sem - not suitable for calling from a fast path.
+ * Call while holding callback_sem.
  **/
 
 int cpuset_excl_nodes_overlap(const struct task_struct *p)
@@ -2166,8 +2193,6 @@ int cpuset_excl_nodes_overlap(const struct task_struct *p)
        const struct cpuset *cs1, *cs2; /* my and p's cpuset ancestors */
        int overlap = 0;                /* do cpusets overlap? */
 
-       down(&callback_sem);
-
        task_lock(current);
        if (current->flags & PF_EXITING) {
                task_unlock(current);
@@ -2186,8 +2211,6 @@ int cpuset_excl_nodes_overlap(const struct task_struct *p)
 
        overlap = nodes_intersects(cs1->mems_allowed, cs2->mems_allowed);
 done:
-       up(&callback_sem);
-
        return overlap;
 }
 
index f8e609ff1893f2d85f76f4b56cba97135b97d152..93cee3671332352f8e4c0f7f9566d9086dd14354 100644 (file)
@@ -193,7 +193,7 @@ int is_orphaned_pgrp(int pgrp)
        return retval;
 }
 
-static inline int has_stopped_jobs(int pgrp)
+static int has_stopped_jobs(int pgrp)
 {
        int retval = 0;
        struct task_struct *p;
@@ -230,7 +230,7 @@ static inline int has_stopped_jobs(int pgrp)
  *
  * NOTE that reparent_to_init() gives the caller full capabilities.
  */
-static inline void reparent_to_init(void)
+static void reparent_to_init(void)
 {
        write_lock_irq(&tasklist_lock);
 
@@ -244,7 +244,9 @@ static inline void reparent_to_init(void)
        /* Set the exit signal to SIGCHLD so we signal init on exit */
        current->exit_signal = SIGCHLD;
 
-       if ((current->policy == SCHED_NORMAL) && (task_nice(current) < 0))
+       if ((current->policy == SCHED_NORMAL ||
+                       current->policy == SCHED_BATCH)
+                               && (task_nice(current) < 0))
                set_user_nice(current, 0);
        /* cpus_allowed? */
        /* rt_priority? */
@@ -367,7 +369,7 @@ void daemonize(const char *name, ...)
 
 EXPORT_SYMBOL(daemonize);
 
-static inline void close_files(struct files_struct * files)
+static void close_files(struct files_struct * files)
 {
        int i, j;
        struct fdtable *fdt;
@@ -541,7 +543,7 @@ static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_re
        p->real_parent = reaper;
 }
 
-static inline void reparent_thread(task_t *p, task_t *father, int traced)
+static void reparent_thread(task_t *p, task_t *father, int traced)
 {
        /* We don't want people slaying init.  */
        if (p->exit_signal != -1)
@@ -605,7 +607,7 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
  * group, and if no such member exists, give it to
  * the global child reaper process (ie "init")
  */
-static inline void forget_original_parent(struct task_struct * father,
+static void forget_original_parent(struct task_struct * father,
                                          struct list_head *to_release)
 {
        struct task_struct *p, *reaper = father;
index 9e66e614862afd20acb0d1190dcb12f9a2101488..197208b3aa2ad837517d27662e5bacaafd75258b 100644 (file)
@@ -192,7 +192,7 @@ static inline int common_clock_set(const clockid_t which_clock,
        return do_sys_settimeofday(tp, NULL);
 }
 
-static inline int common_timer_create(struct k_itimer *new_timer)
+static int common_timer_create(struct k_itimer *new_timer)
 {
        hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock);
        new_timer->it.real.timer.data = new_timer;
@@ -361,7 +361,7 @@ static int posix_timer_fn(void *data)
        return ret;
 }
 
-static inline struct task_struct * good_sigevent(sigevent_t * event)
+static struct task_struct * good_sigevent(sigevent_t * event)
 {
        struct task_struct *rtn = current->group_leader;
 
@@ -687,7 +687,7 @@ sys_timer_getoverrun(timer_t timer_id)
 
 /* Set a POSIX.1b interval timer. */
 /* timr->it_lock is taken. */
-static inline int
+static int
 common_timer_set(struct k_itimer *timr, int flags,
                 struct itimerspec *new_setting, struct itimerspec *old_setting)
 {
@@ -829,7 +829,7 @@ retry_delete:
 /*
  * return timer owned by the process, used by exit_itimers
  */
-static inline void itimer_delete(struct k_itimer *timer)
+static void itimer_delete(struct k_itimer *timer)
 {
        unsigned long flags;
 
index c9dec2aa19760c9dd54905556181692054ade31e..788ecce1e0e4d98701432bc6575cab35c3db3ad5 100644 (file)
@@ -521,7 +521,7 @@ static inline void sched_info_dequeued(task_t *t)
  * long it was waiting to run.  We also note when it began so that we
  * can keep stats on how long its timeslice is.
  */
-static inline void sched_info_arrive(task_t *t)
+static void sched_info_arrive(task_t *t)
 {
        unsigned long now = jiffies, diff = 0;
        struct runqueue *rq = task_rq(t);
@@ -748,10 +748,14 @@ static int recalc_task_prio(task_t *p, unsigned long long now)
        unsigned long long __sleep_time = now - p->timestamp;
        unsigned long sleep_time;
 
-       if (__sleep_time > NS_MAX_SLEEP_AVG)
-               sleep_time = NS_MAX_SLEEP_AVG;
-       else
-               sleep_time = (unsigned long)__sleep_time;
+       if (unlikely(p->policy == SCHED_BATCH))
+               sleep_time = 0;
+       else {
+               if (__sleep_time > NS_MAX_SLEEP_AVG)
+                       sleep_time = NS_MAX_SLEEP_AVG;
+               else
+                       sleep_time = (unsigned long)__sleep_time;
+       }
 
        if (likely(sleep_time > 0)) {
                /*
@@ -1003,7 +1007,7 @@ void kick_process(task_t *p)
  * We want to under-estimate the load of migration sources, to
  * balance conservatively.
  */
-static inline unsigned long __source_load(int cpu, int type, enum idle_type idle)
+static unsigned long __source_load(int cpu, int type, enum idle_type idle)
 {
        runqueue_t *rq = cpu_rq(cpu);
        unsigned long running = rq->nr_running;
@@ -1866,7 +1870,7 @@ void sched_exec(void)
  * pull_task - move a task from a remote runqueue to the local runqueue.
  * Both runqueues must be locked.
  */
-static inline
+static
 void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
               runqueue_t *this_rq, prio_array_t *this_array, int this_cpu)
 {
@@ -1888,7 +1892,7 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
 /*
  * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
  */
-static inline
+static
 int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
                     struct sched_domain *sd, enum idle_type idle,
                     int *all_pinned)
@@ -2374,7 +2378,7 @@ out_balanced:
  * idle_balance is called by schedule() if this_cpu is about to become
  * idle. Attempts to pull tasks from other CPUs.
  */
-static inline void idle_balance(int this_cpu, runqueue_t *this_rq)
+static void idle_balance(int this_cpu, runqueue_t *this_rq)
 {
        struct sched_domain *sd;
 
@@ -2758,7 +2762,7 @@ static inline void wakeup_busy_runqueue(runqueue_t *rq)
                resched_task(rq->idle);
 }
 
-static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
+static void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
 {
        struct sched_domain *tmp, *sd = NULL;
        cpumask_t sibling_map;
@@ -2812,7 +2816,7 @@ static inline unsigned long smt_slice(task_t *p, struct sched_domain *sd)
        return p->time_slice * (100 - sd->per_cpu_gain) / 100;
 }
 
-static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
+static int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
 {
        struct sched_domain *tmp, *sd = NULL;
        cpumask_t sibling_map;
@@ -3560,7 +3564,7 @@ void set_user_nice(task_t *p, long nice)
         * The RT priorities are set via sched_setscheduler(), but we still
         * allow the 'normal' nice value to be set - but as expected
         * it wont have any effect on scheduling until the task is
-        * not SCHED_NORMAL:
+        * not SCHED_NORMAL/SCHED_BATCH:
         */
        if (rt_task(p)) {
                p->static_prio = NICE_TO_PRIO(nice);
@@ -3706,10 +3710,16 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
        BUG_ON(p->array);
        p->policy = policy;
        p->rt_priority = prio;
-       if (policy != SCHED_NORMAL)
+       if (policy != SCHED_NORMAL && policy != SCHED_BATCH) {
                p->prio = MAX_RT_PRIO-1 - p->rt_priority;
-       else
+       } else {
                p->prio = p->static_prio;
+               /*
+                * SCHED_BATCH tasks are treated as perpetual CPU hogs:
+                */
+               if (policy == SCHED_BATCH)
+                       p->sleep_avg = 0;
+       }
 }
 
 /**
@@ -3733,29 +3743,35 @@ recheck:
        if (policy < 0)
                policy = oldpolicy = p->policy;
        else if (policy != SCHED_FIFO && policy != SCHED_RR &&
-                               policy != SCHED_NORMAL)
-                       return -EINVAL;
+                       policy != SCHED_NORMAL && policy != SCHED_BATCH)
+               return -EINVAL;
        /*
         * Valid priorities for SCHED_FIFO and SCHED_RR are
-        * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL is 0.
+        * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL and
+        * SCHED_BATCH is 0.
         */
        if (param->sched_priority < 0 ||
            (p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) ||
            (!p->mm && param->sched_priority > MAX_RT_PRIO-1))
                return -EINVAL;
-       if ((policy == SCHED_NORMAL) != (param->sched_priority == 0))
+       if ((policy == SCHED_NORMAL || policy == SCHED_BATCH)
+                                       != (param->sched_priority == 0))
                return -EINVAL;
 
        /*
         * Allow unprivileged RT tasks to decrease priority:
         */
        if (!capable(CAP_SYS_NICE)) {
-               /* can't change policy */
-               if (policy != p->policy &&
-                       !p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+               /*
+                * can't change policy, except between SCHED_NORMAL
+                * and SCHED_BATCH:
+                */
+               if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
+                       (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&
+                               !p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
                        return -EPERM;
                /* can't increase priority */
-               if (policy != SCHED_NORMAL &&
+               if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) &&
                    param->sched_priority > p->rt_priority &&
                    param->sched_priority >
                                p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
@@ -4233,6 +4249,7 @@ asmlinkage long sys_sched_get_priority_max(int policy)
                ret = MAX_USER_RT_PRIO-1;
                break;
        case SCHED_NORMAL:
+       case SCHED_BATCH:
                ret = 0;
                break;
        }
@@ -4256,6 +4273,7 @@ asmlinkage long sys_sched_get_priority_min(int policy)
                ret = 1;
                break;
        case SCHED_NORMAL:
+       case SCHED_BATCH:
                ret = 0;
        }
        return ret;
@@ -5990,7 +6008,7 @@ next_sg:
  * Detach sched domains from a group of cpus specified in cpu_map
  * These cpus will now be attached to the NULL domain
  */
-static inline void detach_destroy_domains(const cpumask_t *cpu_map)
+static void detach_destroy_domains(const cpumask_t *cpu_map)
 {
        int i;
 
index 1da2e74beb97240947ebe3da5a30a4c5ae81a8fe..5dafbd36d62e0e1a7245dfa35befcfa28876994c 100644 (file)
@@ -476,7 +476,7 @@ unblock_all_signals(void)
        spin_unlock_irqrestore(&current->sighand->siglock, flags);
 }
 
-static inline int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
+static int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
 {
        struct sigqueue *q, *first = NULL;
        int still_pending = 0;
@@ -1881,7 +1881,7 @@ do_signal_stop(int signr)
  * We return zero if we still hold the siglock and should look
  * for another signal without checking group_stop_count again.
  */
-static inline int handle_group_stop(void)
+static int handle_group_stop(void)
 {
        int stop_count;
 
index 62d4d9566876eb9e32199c3969d61d306543d708..f5d69b6e29f50fb051b8ecf1add5964865c105f4 100644 (file)
@@ -648,7 +648,7 @@ static ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-#if defined(CONFIG_S390)
+#if defined(CONFIG_S390) && defined(CONFIG_SMP)
        {
                .ctl_name       = KERN_SPIN_RETRY,
                .procname       = "spin_retry",
index 82c4fa70595cce5c929b8e431047d882749d0227..b052e2c4c71053720e87606e20924cfec5f3f27c 100644 (file)
@@ -147,7 +147,7 @@ int fastcall queue_delayed_work(struct workqueue_struct *wq,
        return ret;
 }
 
-static inline void run_workqueue(struct cpu_workqueue_struct *cwq)
+static void run_workqueue(struct cpu_workqueue_struct *cwq)
 {
        unsigned long flags;
 
index a609235a517f5b52ed7897366a14624e47bd4c12..a314e663d517786a07023b0bbfa1bc3bdfadcc69 100644 (file)
@@ -195,6 +195,20 @@ config FRAME_POINTER
          some architectures or if you use external debuggers.
          If you don't debug the kernel, you can say N.
 
+config FORCED_INLINING
+       bool "Force gcc to inline functions marked 'inline'"
+       depends on DEBUG_KERNEL
+       default y
+       help
+         This option determines if the kernel forces gcc to inline the functions
+         developers have marked 'inline'. Doing so takes away freedom from gcc to
+         do what it thinks is best, which is desirable for the gcc 3.x series of
+         compilers. The gcc 4.x series have a rewritten inlining algorithm and
+         disabling this option will generate a smaller kernel there. Hopefully
+         this algorithm is so good that allowing gcc4 to make the decision can
+         become the default in the future, until then this option is there to
+         test gcc for this.
+
 config RCU_TORTURE_TEST
        tristate "torture tests for RCU"
        depends on DEBUG_KERNEL
index b62cab575a84bb241dad5c1c91717d97a97d2c4d..3171f884d2459a30ad113d9008b82b04d833671c 100644 (file)
@@ -1359,6 +1359,30 @@ restart:
        return 0;
 }
 
+void mpol_shared_policy_init(struct shared_policy *info, int policy,
+                               nodemask_t *policy_nodes)
+{
+       info->root = RB_ROOT;
+       spin_lock_init(&info->lock);
+
+       if (policy != MPOL_DEFAULT) {
+               struct mempolicy *newpol;
+
+               /* Falls back to MPOL_DEFAULT on any error */
+               newpol = mpol_new(policy, policy_nodes);
+               if (!IS_ERR(newpol)) {
+                       /* Create pseudo-vma that contains just the policy */
+                       struct vm_area_struct pvma;
+
+                       memset(&pvma, 0, sizeof(struct vm_area_struct));
+                       /* Policy covers entire file */
+                       pvma.vm_end = TASK_SIZE;
+                       mpol_set_shared_policy(info, &pvma, newpol);
+                       mpol_free(newpol);
+               }
+       }
+}
+
 int mpol_set_shared_policy(struct shared_policy *info,
                        struct vm_area_struct *vma, struct mempolicy *npol)
 {
index 4748b906aff23451c9bbf838ddc1add16bbf1cc9..14bd4ec7959736106b1d2574e1fdd82f999242bf 100644 (file)
@@ -274,6 +274,7 @@ void out_of_memory(gfp_t gfp_mask, int order)
                show_mem();
        }
 
+       cpuset_lock();
        read_lock(&tasklist_lock);
 retry:
        p = select_bad_process();
@@ -284,6 +285,7 @@ retry:
        /* Found nothing?!?! Either we hang forever, or we panic. */
        if (!p) {
                read_unlock(&tasklist_lock);
+               cpuset_unlock();
                panic("Out of memory and no killable processes...\n");
        }
 
@@ -293,6 +295,7 @@ retry:
 
  out:
        read_unlock(&tasklist_lock);
+       cpuset_unlock();
        if (mm)
                mmput(mm);
 
index 343b3c0937e56712e6cd94bf6e764e23acb49143..ce501bce1c2e2369959666de3923e0085112bb73 100644 (file)
@@ -1316,7 +1316,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
                case S_IFREG:
                        inode->i_op = &shmem_inode_operations;
                        inode->i_fop = &shmem_file_operations;
-                       mpol_shared_policy_init(&info->policy);
+                       mpol_shared_policy_init(&info->policy, sbinfo->policy,
+                                                       &sbinfo->policy_nodes);
                        break;
                case S_IFDIR:
                        inode->i_nlink++;
@@ -1330,7 +1331,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
                         * Must not load anything in the rbtree,
                         * mpol_free_shared_policy will not be called.
                         */
-                       mpol_shared_policy_init(&info->policy);
+                       mpol_shared_policy_init(&info->policy, MPOL_DEFAULT,
+                                               NULL);
                        break;
                }
        } else if (sbinfo->max_inodes) {
@@ -1843,7 +1845,9 @@ static struct inode_operations shmem_symlink_inode_operations = {
        .put_link       = shmem_put_link,
 };
 
-static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
+static int shmem_parse_options(char *options, int *mode, uid_t *uid,
+       gid_t *gid, unsigned long *blocks, unsigned long *inodes,
+       int *policy, nodemask_t *policy_nodes)
 {
        char *this_char, *value, *rest;
 
@@ -1897,6 +1901,19 @@ static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid,
                        *gid = simple_strtoul(value,&rest,0);
                        if (*rest)
                                goto bad_val;
+               } else if (!strcmp(this_char,"mpol")) {
+                       if (!strcmp(value,"default"))
+                               *policy = MPOL_DEFAULT;
+                       else if (!strcmp(value,"preferred"))
+                               *policy = MPOL_PREFERRED;
+                       else if (!strcmp(value,"bind"))
+                               *policy = MPOL_BIND;
+                       else if (!strcmp(value,"interleave"))
+                               *policy = MPOL_INTERLEAVE;
+                       else
+                               goto bad_val;
+               } else if (!strcmp(this_char,"mpol_nodelist")) {
+                       nodelist_parse(value, *policy_nodes);
                } else {
                        printk(KERN_ERR "tmpfs: Bad mount option %s\n",
                               this_char);
@@ -1917,12 +1934,14 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
        unsigned long max_blocks = sbinfo->max_blocks;
        unsigned long max_inodes = sbinfo->max_inodes;
+       int policy = sbinfo->policy;
+       nodemask_t policy_nodes = sbinfo->policy_nodes;
        unsigned long blocks;
        unsigned long inodes;
        int error = -EINVAL;
 
-       if (shmem_parse_options(data, NULL, NULL, NULL,
-                               &max_blocks, &max_inodes))
+       if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks,
+                               &max_inodes, &policy, &policy_nodes))
                return error;
 
        spin_lock(&sbinfo->stat_lock);
@@ -1948,6 +1967,8 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
        sbinfo->free_blocks = max_blocks - blocks;
        sbinfo->max_inodes  = max_inodes;
        sbinfo->free_inodes = max_inodes - inodes;
+       sbinfo->policy = policy;
+       sbinfo->policy_nodes = policy_nodes;
 out:
        spin_unlock(&sbinfo->stat_lock);
        return error;
@@ -1972,6 +1993,8 @@ static int shmem_fill_super(struct super_block *sb,
        struct shmem_sb_info *sbinfo;
        unsigned long blocks = 0;
        unsigned long inodes = 0;
+       int policy = MPOL_DEFAULT;
+       nodemask_t policy_nodes = node_online_map;
 
 #ifdef CONFIG_TMPFS
        /*
@@ -1984,8 +2007,8 @@ static int shmem_fill_super(struct super_block *sb,
                inodes = totalram_pages - totalhigh_pages;
                if (inodes > blocks)
                        inodes = blocks;
-               if (shmem_parse_options(data, &mode, &uid, &gid,
-                                       &blocks, &inodes))
+               if (shmem_parse_options(data, &mode, &uid, &gid, &blocks,
+                                       &inodes, &policy, &policy_nodes))
                        return -EINVAL;
        }
 #else
@@ -2003,6 +2026,8 @@ static int shmem_fill_super(struct super_block *sb,
        sbinfo->free_blocks = blocks;
        sbinfo->max_inodes = inodes;
        sbinfo->free_inodes = inodes;
+       sbinfo->policy = policy;
+       sbinfo->policy_nodes = policy_nodes;
 
        sb->s_fs_info = sbinfo;
        sb->s_maxbytes = SHMEM_MAX_BYTES;
index 60f6f321bd7667a9d57ed03edb17c88ac0e4a0dc..9296b269d675771861bf1b2fc596dd31284faeeb 100644 (file)
@@ -159,6 +159,7 @@ source "net/ipx/Kconfig"
 source "drivers/net/appletalk/Kconfig"
 source "net/x25/Kconfig"
 source "net/lapb/Kconfig"
+source "net/tipc/Kconfig"
 
 config NET_DIVERT
        bool "Frame Diverter (EXPERIMENTAL)"
index f5141b9d4f38ff94e7a696438bbaa2e9de9f3214..065796f5fb17701f550bcd5197fe30d35ec986cb 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_VLAN_8021Q)      += 8021q/
 obj-$(CONFIG_IP_DCCP)          += dccp/
 obj-$(CONFIG_IP_SCTP)          += sctp/
 obj-$(CONFIG_IEEE80211)                += ieee80211/
+obj-$(CONFIG_TIPC)             += tipc/
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)           += sysctl_net.o
index 9f6e0193ae100cef83b4952b7a3fc20c70b7a1ae..a29c1232c4204e5a66c45e251039c14575930c97 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/netfilter.h>
 #include <linux/module.h>
 #include <linux/ip.h>
+#include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/spinlock.h>
 
index 9eb9d0017a01810e37c42f142bbdadbdb3cfee3e..a52665f752240a6e48300d89403d1706675c6ee5 100644 (file)
@@ -287,7 +287,9 @@ load_b:
  * no references or jumps that are out of range, no illegal
  * instructions, and must end with a RET instruction.
  *
- * Returns 0 if the rule set is legal or a negative errno code if not.
+ * All jumps are forward as they are not signed.
+ *
+ * Returns 0 if the rule set is legal or -EINVAL if not.
  */
 int sk_chk_filter(struct sock_filter *filter, int flen)
 {
@@ -299,7 +301,6 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
 
        /* check the filter code now */
        for (pc = 0; pc < flen; pc++) {
-               /* all jumps are forward as they are not signed */
                ftest = &filter[pc];
 
                /* Only allow valid instructions */
@@ -383,11 +384,6 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
                }
        }
 
-       /*
-        * The program must end with a return. We don't care where they
-        * jumped within the script (its always forwards) but in the end
-        * they _will_ hit this.
-        */
         return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL;
 }
 
index 321287bc887f2808438af09f9e955d78828063bd..90d18b72da3dc2d470a2a0a5a37531c10caf374c 100644 (file)
@@ -62,7 +62,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION);
 MODULE_AUTHOR(DRV_COPYRIGHT);
 MODULE_LICENSE("GPL");
 
-static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
+static int ieee80211_networks_allocate(struct ieee80211_device *ieee)
 {
        if (ieee->networks)
                return 0;
@@ -90,7 +90,7 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
        ieee->networks = NULL;
 }
 
-static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee)
+static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
 {
        int i;
 
index 5e33803880469eef972ffdee7ebc4c3404fd16b1..7a121802faa92d7aa33b07734d8c6a0f3165662e 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <net/ieee80211.h>
 
-static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee,
+static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
                                        struct sk_buff *skb,
                                        struct ieee80211_rx_stats *rx_stats)
 {
@@ -165,7 +165,7 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,
  * Responsible for handling management control frames
  *
  * Called by ieee80211_rx */
-static inline int
+static int
 ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
                        struct ieee80211_rx_stats *rx_stats, u16 type,
                        u16 stype)
@@ -266,7 +266,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee,
 }
 
 /* Called only as a tasklet (software IRQ), by ieee80211_rx */
-static inline int
+static int
 ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
                           struct ieee80211_crypt_data *crypt)
 {
@@ -297,7 +297,7 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb,
 }
 
 /* Called only as a tasklet (software IRQ), by ieee80211_rx */
-static inline int
+static int
 ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee,
                                struct sk_buff *skb, int keyidx,
                                struct ieee80211_crypt_data *crypt)
@@ -1156,7 +1156,7 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee
 
 /***************************************************/
 
-static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
+static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response
                                         *beacon,
                                         struct ieee80211_network *network,
                                         struct ieee80211_rx_stats *stats)
@@ -1235,7 +1235,7 @@ static inline int is_same_network(struct ieee80211_network *src,
                !memcmp(src->ssid, dst->ssid, src->ssid_len));
 }
 
-static inline void update_network(struct ieee80211_network *dst,
+static void update_network(struct ieee80211_network *dst,
                                  struct ieee80211_network *src)
 {
        int qos_active;
@@ -1294,7 +1294,7 @@ static inline int is_beacon(int fc)
        return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
 }
 
-static inline void ieee80211_process_probe_response(struct ieee80211_device
+static void ieee80211_process_probe_response(struct ieee80211_device
                                                    *ieee, struct
                                                    ieee80211_probe_response
                                                    *beacon, struct ieee80211_rx_stats
index e5b33c8d5dbcc0e683cc3f4daf60eb7532ff8d9b..8fdd943ebe8e21864223a4c9e4742322becc2050 100644 (file)
@@ -127,7 +127,7 @@ payload of each frame is reduced to 492 bytes.
 static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
 static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
 
-static inline int ieee80211_copy_snap(u8 * data, u16 h_proto)
+static int ieee80211_copy_snap(u8 * data, u16 h_proto)
 {
        struct ieee80211_snap_hdr *snap;
        u8 *oui;
@@ -150,7 +150,7 @@ static inline int ieee80211_copy_snap(u8 * data, u16 h_proto)
        return SNAP_SIZE + sizeof(u16);
 }
 
-static inline int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
+static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee,
                                             struct sk_buff *frag, int hdr_len)
 {
        struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
index 406d5b9649059f5ea9af820609db8577029cb015..23e1630f50b7cf872e01286c01a108cbc66c478f 100644 (file)
@@ -42,7 +42,7 @@ static const char *ieee80211_modes[] = {
 };
 
 #define MAX_CUSTOM_LEN 64
-static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
+static char *ipw2100_translate_scan(struct ieee80211_device *ieee,
                                           char *start, char *stop,
                                           struct ieee80211_network *network)
 {
index 5b25fc0d980c98655dc20814f0ba432cffcbb9e9..4e3d3811dea29f67c2cd701368ea3bb6a0c677a8 100644 (file)
@@ -289,13 +289,13 @@ static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
        int i;
 
-       for (i=1; i<=RTA_MAX; i++) {
-               struct rtattr *attr = rta[i-1];
+       for (i=1; i<=RTA_MAX; i++, rta++) {
+               struct rtattr *attr = *rta;
                if (attr) {
                        if (RTA_PAYLOAD(attr) < 4)
                                return -EINVAL;
                        if (i != RTA_MULTIPATH && i != RTA_METRICS)
-                               rta[i-1] = (struct rtattr*)RTA_DATA(attr);
+                               *rta = (struct rtattr*)RTA_DATA(attr);
                }
        }
        return 0;
index a9893ec03e029e8b4a656c980399d66bbed5a753..db783036e4d8fbdf691418c114acf39396cba258 100644 (file)
@@ -182,6 +182,7 @@ config IP_NF_QUEUE
 
 config IP_NF_IPTABLES
        tristate "IP tables support (required for filtering/masq/NAT)"
+       depends on NETFILTER_XTABLES
        help
          iptables is a general, extensible packet identification framework.
          The packet filtering and full NAT (masquerading, port forwarding,
@@ -191,16 +192,6 @@ config IP_NF_IPTABLES
          To compile it as a module, choose M here.  If unsure, say N.
 
 # The matches.
-config IP_NF_MATCH_LIMIT
-       tristate "limit match support"
-       depends on IP_NF_IPTABLES
-       help
-         limit matching allows you to control the rate at which a rule can be
-         matched: mainly useful in combination with the LOG target ("LOG
-         target support", below) and to avoid some Denial of Service attacks.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_IPRANGE
        tristate "IP range match support"
        depends on IP_NF_IPTABLES
@@ -210,37 +201,6 @@ config IP_NF_MATCH_IPRANGE
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_MAC
-       tristate "MAC address match support"
-       depends on IP_NF_IPTABLES
-       help
-         MAC matching allows you to match packets based on the source
-         Ethernet address of the packet.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_PKTTYPE
-       tristate "Packet type match support"
-       depends on IP_NF_IPTABLES
-       help
-         Packet type matching allows you to match a packet by
-         its "class", eg. BROADCAST, MULTICAST, ...
-
-         Typical usage:
-         iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_MARK
-       tristate "netfilter MARK match support"
-       depends on IP_NF_IPTABLES
-       help
-         Netfilter mark matching allows you to match packets based on the
-         `nfmark' value in the packet.  This can be set by the MARK target
-         (see below).
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_MULTIPORT
        tristate "Multiple port match support"
        depends on IP_NF_IPTABLES
@@ -301,15 +261,6 @@ config IP_NF_MATCH_AH_ESP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_LENGTH
-       tristate "LENGTH match support"
-       depends on IP_NF_IPTABLES
-       help
-         This option allows you to match the length of a packet against a
-         specific value or range of values.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_TTL
        tristate "TTL match support"
        depends on IP_NF_IPTABLES
@@ -319,50 +270,6 @@ config IP_NF_MATCH_TTL
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_TCPMSS
-       tristate "tcpmss match support"
-       depends on IP_NF_IPTABLES
-       help
-         This option adds a `tcpmss' match, which allows you to examine the
-         MSS value of TCP SYN packets, which control the maximum packet size
-         for that connection.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_HELPER
-       tristate "Helper match support"
-       depends on IP_NF_IPTABLES
-       depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-       help
-         Helper matching allows you to match packets in dynamic connections
-         tracked by a conntrack-helper, ie. ip_conntrack_ftp
-
-         To compile it as a module, choose M here.  If unsure, say Y.
-
-config IP_NF_MATCH_STATE
-       tristate "Connection state match support"
-       depends on IP_NF_IPTABLES
-       depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-       help
-         Connection state matching allows you to match packets based on their
-         relationship to a tracked connection (ie. previous packets).  This
-         is a powerful tool for packet classification.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_MATCH_CONNTRACK
-       tristate "Connection tracking match support"
-       depends on IP_NF_IPTABLES
-       depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-       help
-         This is a general conntrack match module, a superset of the state match.
-
-         It allows matching on additional conntrack information, which is
-         useful in complex configurations, such as NAT gateways with multiple
-         internet links or tunnels.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_OWNER
        tristate "Owner match support"
        depends on IP_NF_IPTABLES
@@ -372,15 +279,6 @@ config IP_NF_MATCH_OWNER
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_MATCH_PHYSDEV
-       tristate "Physdev match support"
-       depends on IP_NF_IPTABLES && BRIDGE_NETFILTER
-       help
-         Physdev packet matching matches against the physical bridge ports
-         the IP packet arrived on or will leave by.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_ADDRTYPE
        tristate  'address type match support'
        depends on IP_NF_IPTABLES
@@ -391,75 +289,6 @@ config IP_NF_MATCH_ADDRTYPE
          If you want to compile it as a module, say M here and read
          <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-config IP_NF_MATCH_REALM
-       tristate  'realm match support'
-       depends on IP_NF_IPTABLES
-       select NET_CLS_ROUTE
-       help
-         This option adds a `realm' match, which allows you to use the realm
-         key from the routing subsystem inside iptables.
-       
-         This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option 
-         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'.
-
-config IP_NF_MATCH_SCTP
-       tristate  'SCTP protocol match support'
-       depends on IP_NF_IPTABLES
-       help
-         With this option enabled, you will be able to use the iptables
-         `sctp' match in order to match on SCTP source/destination ports
-         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'.
-
-config IP_NF_MATCH_DCCP
-       tristate  'DCCP protocol match support'
-       depends on IP_NF_IPTABLES
-       help
-         With this option enabled, you will be able to use the iptables
-         `dccp' match in order to match on DCCP source/destination ports
-         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'.
-
-config IP_NF_MATCH_COMMENT
-       tristate  'comment match support'
-       depends on IP_NF_IPTABLES
-       help
-         This option adds a `comment' dummy-match, which allows you to put
-         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'.
-
-config IP_NF_MATCH_CONNMARK
-       tristate  'Connection mark match support'
-       depends on IP_NF_IPTABLES
-       depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
-       help
-         This option adds a `connmark' match, which allows you to match the
-         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'.
-
-config IP_NF_MATCH_CONNBYTES
-       tristate  'Connection byte/packet counter match support'
-       depends on IP_NF_IPTABLES
-       depends on (IP_NF_CONNTRACK && IP_NF_CT_ACCT) || (NF_CT_ACCT && NF_CONNTRACK_IPV4)
-       help
-         This option adds a `connbytes' match, which allows you to match the
-         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'.
-
 config IP_NF_MATCH_HASHLIMIT
        tristate  'hashlimit match support'
        depends on IP_NF_IPTABLES
@@ -474,19 +303,6 @@ config IP_NF_MATCH_HASHLIMIT
          destination IP' or `500pps from any given source IP'  with a single
          IPtables rule.
 
-config IP_NF_MATCH_STRING
-       tristate  'string match support'
-       depends on IP_NF_IPTABLES 
-       select TEXTSEARCH
-       select TEXTSEARCH_KMP
-       select TEXTSEARCH_BM
-       select TEXTSEARCH_FSM
-       help
-         This option adds a `string' match, which allows you to look for
-         pattern matchings in packets.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_MATCH_POLICY
        tristate "IPsec policy match support"
        depends on IP_NF_IPTABLES && XFRM
@@ -572,17 +388,6 @@ config IP_NF_TARGET_TCPMSS
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_NFQUEUE
-       tristate "NFQUEUE Target Support"
-       depends on IP_NF_IPTABLES
-       help
-         This Target replaced the old obsolete QUEUE target.
-
-         As opposed to QUEUE, it supports 65535 different queues,
-         not just one.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 # NAT + specific targets
 config IP_NF_NAT
        tristate "Full NAT"
@@ -735,31 +540,6 @@ config IP_NF_TARGET_DSCP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_MARK
-       tristate "MARK target support"
-       depends on IP_NF_MANGLE
-       help
-         This option adds a `MARK' target, which allows you to create rules
-         in the `mangle' table which alter the netfilter mark (nfmark) field
-         associated with the packet prior to routing. This can change
-         the routing method (see `Use netfilter MARK value as routing
-         key') and can also be used by other subsystems to change their
-         behavior.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-config IP_NF_TARGET_CLASSIFY
-       tristate "CLASSIFY target support"
-       depends on IP_NF_MANGLE
-       help
-         This option adds a `CLASSIFY' target, which enables the user to set
-         the priority of a packet. Some qdiscs can use this value for
-         classification, among these are:
-
-         atm, cbq, dsmark, pfifo_fast, htb, prio
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_TARGET_TTL
        tristate  'TTL target support'
        depends on IP_NF_MANGLE
@@ -774,19 +554,6 @@ config IP_NF_TARGET_TTL
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP_NF_TARGET_CONNMARK
-       tristate  'CONNMARK target support'
-       depends on IP_NF_MANGLE
-       depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
-       help
-         This option adds a `CONNMARK' target, which allows one to manipulate
-         the connection mark value.  Similar to the MARK target, but
-         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'.
-
 config IP_NF_TARGET_CLUSTERIP
        tristate "CLUSTERIP target support (EXPERIMENTAL)"
        depends on IP_NF_MANGLE && EXPERIMENTAL
@@ -810,23 +577,10 @@ config IP_NF_RAW
          If you want to compile it as a module, say M here and read
          <file:Documentation/modules.txt>.  If unsure, say `N'.
 
-config IP_NF_TARGET_NOTRACK
-       tristate  'NOTRACK target support'
-       depends on IP_NF_RAW
-       depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
-       help
-         The NOTRACK target allows a select rule to specify
-         which packets *not* to enter the conntrack/NAT
-         subsystem with all the consequences (no ICMP error tracking,
-         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'.
-
-
 # ARP tables
 config IP_NF_ARPTABLES
        tristate "ARP tables support"
+       depends on NETFILTER_XTABLES
        help
          arptables is a general, extensible packet identification framework.
          The ARP packet filtering and mangling (manipulation)subsystems
index 549b01a648b31e41f755621b849c5c5164e4afb6..bcefe64b93177c7e4705065c6f909f46eb7a06e2 100644 (file)
@@ -47,14 +47,8 @@ obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
 
 # matches
 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
-obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
 obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
-obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
-obj-$(CONFIG_IP_NF_MATCH_DCCP) += ipt_dccp.o
-obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
-obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
-obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
@@ -62,40 +56,25 @@ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
 obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
-obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
-obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
-obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
-obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
-obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
-obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
-obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
 obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
-obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
 obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o
-obj-$(CONFIG_IP_NF_MATCH_COMMENT) += ipt_comment.o
-obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
 
 # targets
 obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
 obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
 obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
 obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
-obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
-obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
-obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
-obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
 obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
 obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
-obj-$(CONFIG_IP_NF_TARGET_NFQUEUE) += ipt_NFQUEUE.o
 
 # generic ARP tables
 obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
index b6d5284c8020760685bcbf529e65525a915b8af4..afe3d8f8177d7df83df0264e20f3072077ff1317 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_arp/arp_tables.h>
 
 MODULE_LICENSE("GPL");
@@ -55,28 +56,9 @@ do {                                                         \
 #else
 #define ARP_NF_ASSERT(x)
 #endif
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
-static DECLARE_MUTEX(arpt_mutex);
-
-#define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
-#define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
 #include <linux/netfilter_ipv4/listhelp.h>
 
-struct arpt_table_info {
-       unsigned int size;
-       unsigned int number;
-       unsigned int initial_entries;
-       unsigned int hook_entry[NF_ARP_NUMHOOKS];
-       unsigned int underflow[NF_ARP_NUMHOOKS];
-       void *entries[NR_CPUS];
-};
-
-static LIST_HEAD(arpt_target);
-static LIST_HEAD(arpt_tables);
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
 static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
                                      char *hdr_addr, int len)
 {
@@ -223,9 +205,9 @@ static inline int arp_checkentry(const struct arpt_arp *arp)
 }
 
 static unsigned int arpt_error(struct sk_buff **pskb,
-                              unsigned int hooknum,
                               const struct net_device *in,
                               const struct net_device *out,
+                              unsigned int hooknum,
                               const void *targinfo,
                               void *userinfo)
 {
@@ -254,6 +236,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
        struct arpt_entry *e, *back;
        const char *indev, *outdev;
        void *table_base;
+       struct xt_table_info *private = table->private;
 
        /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
        if (!pskb_may_pull((*pskb), (sizeof(struct arphdr) +
@@ -265,9 +248,9 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
        outdev = out ? out->name : nulldevname;
 
        read_lock_bh(&table->lock);
-       table_base = (void *)table->private->entries[smp_processor_id()];
-       e = get_entry(table_base, table->private->hook_entry[hook]);
-       back = get_entry(table_base, table->private->underflow[hook]);
+       table_base = (void *)private->entries[smp_processor_id()];
+       e = get_entry(table_base, private->hook_entry[hook]);
+       back = get_entry(table_base, private->underflow[hook]);
 
        arp = (*pskb)->nh.arph;
        do {
@@ -315,8 +298,8 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
                                 * abs. verdicts
                                 */
                                verdict = t->u.kernel.target->target(pskb,
-                                                                    hook,
                                                                     in, out,
+                                                                    hook,
                                                                     t->data,
                                                                     userdata);
 
@@ -341,106 +324,6 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
                return verdict;
 }
 
-/*
- * These are weird, but module loading must not be done with mutex
- * held (since they will register), and we have to have a single
- * function to use try_then_request_module().
- */
-
-/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-static inline struct arpt_table *find_table_lock(const char *name)
-{
-       struct arpt_table *t;
-
-       if (down_interruptible(&arpt_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(t, &arpt_tables, list)
-               if (strcmp(t->name, name) == 0 && try_module_get(t->me))
-                       return t;
-       up(&arpt_mutex);
-       return NULL;
-}
-
-
-/* Find target, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct arpt_target *find_target(const char *name, u8 revision)
-{
-       struct arpt_target *t;
-       int err = 0;
-
-       if (down_interruptible(&arpt_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(t, &arpt_target, list) {
-               if (strcmp(t->name, name) == 0) {
-                       if (t->revision == revision) {
-                               if (try_module_get(t->me)) {
-                                       up(&arpt_mutex);
-                                       return t;
-                               }
-                       } else
-                               err = -EPROTOTYPE; /* Found something. */
-               }
-       }
-       up(&arpt_mutex);
-       return ERR_PTR(err);
-}
-
-struct arpt_target *arpt_find_target(const char *name, u8 revision)
-{
-       struct arpt_target *target;
-
-       target = try_then_request_module(find_target(name, revision),
-                                        "arpt_%s", name);
-       if (IS_ERR(target) || !target)
-               return NULL;
-       return target;
-}
-
-static int target_revfn(const char *name, u8 revision, int *bestp)
-{
-       struct arpt_target *t;
-       int have_rev = 0;
-
-       list_for_each_entry(t, &arpt_target, list) {
-               if (strcmp(t->name, name) == 0) {
-                       if (t->revision > *bestp)
-                               *bestp = t->revision;
-                       if (t->revision == revision)
-                               have_rev =1;
-               }
-       }
-       return have_rev;
-}
-
-/* Returns true or false (if no such extension at all) */
-static inline int find_revision(const char *name, u8 revision,
-                               int (*revfn)(const char *, u8, int *),
-                               int *err)
-{
-       int have_rev, best = -1;
-
-       if (down_interruptible(&arpt_mutex) != 0) {
-               *err = -EINTR;
-               return 1;
-       }
-       have_rev = revfn(name, revision, &best);
-       up(&arpt_mutex);
-
-       /* Nothing at all?  Return 0 to try loading module. */
-       if (best == -1) {
-               *err = -ENOENT;
-               return 0;
-       }
-
-       *err = best;
-       if (!have_rev)
-               *err = -EPROTONOSUPPORT;
-       return 1;
-}
-
-
 /* All zeroes == unconditional rule. */
 static inline int unconditional(const struct arpt_arp *arp)
 {
@@ -456,7 +339,7 @@ static inline int unconditional(const struct arpt_arp *arp)
 /* Figures out from what hook each rule can be called: returns 0 if
  * there are loops.  Puts hook bitmask in comefrom.
  */
-static int mark_source_chains(struct arpt_table_info *newinfo,
+static int mark_source_chains(struct xt_table_info *newinfo,
                              unsigned int valid_hooks, void *entry0)
 {
        unsigned int hook;
@@ -587,8 +470,8 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
        }
 
        t = arpt_get_target(e);
-       target = try_then_request_module(find_target(t->u.user.name,
-                                                    t->u.user.revision),
+       target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
+                                                       t->u.user.revision),
                                         "arpt_%s", t->u.user.name);
        if (IS_ERR(target) || !target) {
                duprintf("check_entry: `%s' not found\n", t->u.user.name);
@@ -622,7 +505,7 @@ out:
 }
 
 static inline int check_entry_size_and_hooks(struct arpt_entry *e,
-                                            struct arpt_table_info *newinfo,
+                                            struct xt_table_info *newinfo,
                                             unsigned char *base,
                                             unsigned char *limit,
                                             const unsigned int *hook_entries,
@@ -656,7 +539,7 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e,
            < 0 (not ARPT_RETURN). --RR */
 
        /* Clear counters and comefrom */
-       e->counters = ((struct arpt_counters) { 0, 0 });
+       e->counters = ((struct xt_counters) { 0, 0 });
        e->comefrom = 0;
 
        (*i)++;
@@ -683,7 +566,7 @@ static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i)
  */
 static int translate_table(const char *name,
                           unsigned int valid_hooks,
-                          struct arpt_table_info *newinfo,
+                          struct xt_table_info *newinfo,
                           void *entry0,
                           unsigned int size,
                           unsigned int number,
@@ -764,34 +647,9 @@ static int translate_table(const char *name,
        return ret;
 }
 
-static struct arpt_table_info *replace_table(struct arpt_table *table,
-                                            unsigned int num_counters,
-                                            struct arpt_table_info *newinfo,
-                                            int *error)
-{
-       struct arpt_table_info *oldinfo;
-
-       /* Do the substitution. */
-       write_lock_bh(&table->lock);
-       /* Check inside lock: is the old number correct? */
-       if (num_counters != table->private->number) {
-               duprintf("num_counters != table->private->number (%u/%u)\n",
-                        num_counters, table->private->number);
-               write_unlock_bh(&table->lock);
-               *error = -EAGAIN;
-               return NULL;
-       }
-       oldinfo = table->private;
-       table->private = newinfo;
-       newinfo->initial_entries = oldinfo->initial_entries;
-       write_unlock_bh(&table->lock);
-
-       return oldinfo;
-}
-
 /* Gets counters. */
 static inline int add_entry_to_counter(const struct arpt_entry *e,
-                                      struct arpt_counters total[],
+                                      struct xt_counters total[],
                                       unsigned int *i)
 {
        ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -801,7 +659,7 @@ static inline int add_entry_to_counter(const struct arpt_entry *e,
 }
 
 static inline int set_entry_to_counter(const struct arpt_entry *e,
-                                      struct arpt_counters total[],
+                                      struct xt_counters total[],
                                       unsigned int *i)
 {
        SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -810,8 +668,8 @@ static inline int set_entry_to_counter(const struct arpt_entry *e,
        return 0;
 }
 
-static void get_counters(const struct arpt_table_info *t,
-                        struct arpt_counters counters[])
+static void get_counters(const struct xt_table_info *t,
+                        struct xt_counters counters[])
 {
        unsigned int cpu;
        unsigned int i;
@@ -849,7 +707,8 @@ static int copy_entries_to_user(unsigned int total_size,
 {
        unsigned int off, num, countersize;
        struct arpt_entry *e;
-       struct arpt_counters *counters;
+       struct xt_counters *counters;
+       struct xt_table_info *private = table->private;
        int ret = 0;
        void *loc_cpu_entry;
 
@@ -857,18 +716,18 @@ static int copy_entries_to_user(unsigned int total_size,
         * (other than comefrom, which userspace doesn't care
         * about).
         */
-       countersize = sizeof(struct arpt_counters) * table->private->number;
-       counters = vmalloc(countersize);
+       countersize = sizeof(struct xt_counters) * private->number;
+       counters = vmalloc_node(countersize, numa_node_id());
 
        if (counters == NULL)
                return -ENOMEM;
 
        /* First, sum counters... */
        write_lock_bh(&table->lock);
-       get_counters(table->private, counters);
+       get_counters(private, counters);
        write_unlock_bh(&table->lock);
 
-       loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
        /* ... then copy entire thing ... */
        if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
                ret = -EFAULT;
@@ -911,75 +770,34 @@ static int get_entries(const struct arpt_get_entries *entries,
        int ret;
        struct arpt_table *t;
 
-       t = find_table_lock(entries->name);
+       t = xt_find_table_lock(NF_ARP, entries->name);
        if (t || !IS_ERR(t)) {
+               struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n",
-                        t->private->number);
-               if (entries->size == t->private->size)
-                       ret = copy_entries_to_user(t->private->size,
+                        private->number);
+               if (entries->size == private->size)
+                       ret = copy_entries_to_user(private->size,
                                                   t, uptr->entrytable);
                else {
                        duprintf("get_entries: I've got %u not %u!\n",
-                                t->private->size,
-                                entries->size);
+                                private->size, entries->size);
                        ret = -EINVAL;
                }
                module_put(t->me);
-               up(&arpt_mutex);
+               xt_table_unlock(t);
        } else
                ret = t ? PTR_ERR(t) : -ENOENT;
 
        return ret;
 }
 
-static void free_table_info(struct arpt_table_info *info)
-{
-       int cpu;
-       for_each_cpu(cpu) {
-               if (info->size <= PAGE_SIZE)
-                       kfree(info->entries[cpu]);
-               else
-                       vfree(info->entries[cpu]);
-       }
-       kfree(info);
-}
-
-static struct arpt_table_info *alloc_table_info(unsigned int size)
-{
-       struct arpt_table_info *newinfo;
-       int cpu;
-       
-       newinfo = kzalloc(sizeof(struct arpt_table_info), GFP_KERNEL);
-       if (!newinfo)
-               return NULL;
-
-       newinfo->size = size;
-
-       for_each_cpu(cpu) {
-               if (size <= PAGE_SIZE)
-                       newinfo->entries[cpu] = kmalloc_node(size,
-                                                       GFP_KERNEL,
-                                                       cpu_to_node(cpu));
-               else
-                       newinfo->entries[cpu] = vmalloc_node(size,
-                                                            cpu_to_node(cpu));
-
-               if (newinfo->entries[cpu] == NULL) {
-                       free_table_info(newinfo);
-                       return NULL;
-               }
-       }
-
-       return newinfo;
-}
-
 static int do_replace(void __user *user, unsigned int len)
 {
        int ret;
        struct arpt_replace tmp;
        struct arpt_table *t;
-       struct arpt_table_info *newinfo, *oldinfo;
-       struct arpt_counters *counters;
+       struct xt_table_info *newinfo, *oldinfo;
+       struct xt_counters *counters;
        void *loc_cpu_entry, *loc_cpu_old_entry;
 
        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
@@ -989,11 +807,7 @@ static int do_replace(void __user *user, unsigned int len)
        if (len != sizeof(tmp) + tmp.size)
                return -ENOPROTOOPT;
 
-       /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-       if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
-               return -ENOMEM;
-
-       newinfo = alloc_table_info(tmp.size);
+       newinfo = xt_alloc_table_info(tmp.size);
        if (!newinfo)
                return -ENOMEM;
 
@@ -1005,7 +819,7 @@ static int do_replace(void __user *user, unsigned int len)
                goto free_newinfo;
        }
 
-       counters = vmalloc(tmp.num_counters * sizeof(struct arpt_counters));
+       counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
        if (!counters) {
                ret = -ENOMEM;
                goto free_newinfo;
@@ -1019,7 +833,7 @@ static int do_replace(void __user *user, unsigned int len)
 
        duprintf("arp_tables: Translated table\n");
 
-       t = try_then_request_module(find_table_lock(tmp.name),
+       t = try_then_request_module(xt_find_table_lock(NF_ARP, tmp.name),
                                    "arptable_%s", tmp.name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1034,7 +848,7 @@ static int do_replace(void __user *user, unsigned int len)
                goto put_module;
        }
 
-       oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
+       oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
        if (!oldinfo)
                goto put_module;
 
@@ -1054,23 +868,23 @@ static int do_replace(void __user *user, unsigned int len)
        loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
        ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
 
-       free_table_info(oldinfo);
+       xt_free_table_info(oldinfo);
        if (copy_to_user(tmp.counters, counters,
-                        sizeof(struct arpt_counters) * tmp.num_counters) != 0)
+                        sizeof(struct xt_counters) * tmp.num_counters) != 0)
                ret = -EFAULT;
        vfree(counters);
-       up(&arpt_mutex);
+       xt_table_unlock(t);
        return ret;
 
  put_module:
        module_put(t->me);
-       up(&arpt_mutex);
+       xt_table_unlock(t);
  free_newinfo_counters_untrans:
        ARPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
  free_newinfo_counters:
        vfree(counters);
  free_newinfo:
-       free_table_info(newinfo);
+       xt_free_table_info(newinfo);
        return ret;
 }
 
@@ -1078,7 +892,7 @@ static int do_replace(void __user *user, unsigned int len)
  * and everything is OK.
  */
 static inline int add_counter_to_entry(struct arpt_entry *e,
-                                      const struct arpt_counters addme[],
+                                      const struct xt_counters addme[],
                                       unsigned int *i)
 {
 
@@ -1091,15 +905,16 @@ static inline int add_counter_to_entry(struct arpt_entry *e,
 static int do_add_counters(void __user *user, unsigned int len)
 {
        unsigned int i;
-       struct arpt_counters_info tmp, *paddc;
+       struct xt_counters_info tmp, *paddc;
        struct arpt_table *t;
+       struct xt_table_info *private;
        int ret = 0;
        void *loc_cpu_entry;
 
        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
                return -EFAULT;
 
-       if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct arpt_counters))
+       if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
                return -EINVAL;
 
        paddc = vmalloc(len);
@@ -1111,29 +926,30 @@ static int do_add_counters(void __user *user, unsigned int len)
                goto free;
        }
 
-       t = find_table_lock(tmp.name);
+       t = xt_find_table_lock(NF_ARP, tmp.name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
        }
 
        write_lock_bh(&t->lock);
-       if (t->private->number != paddc->num_counters) {
+       private = t->private;
+       if (private->number != paddc->num_counters) {
                ret = -EINVAL;
                goto unlock_up_free;
        }
 
        i = 0;
        /* Choose the copy that is on our node */
-       loc_cpu_entry = t->private->entries[smp_processor_id()];
+       loc_cpu_entry = private->entries[smp_processor_id()];
        ARPT_ENTRY_ITERATE(loc_cpu_entry,
-                          t->private->size,
+                          private->size,
                           add_counter_to_entry,
                           paddc->counters,
                           &i);
  unlock_up_free:
        write_unlock_bh(&t->lock);
-       up(&arpt_mutex);
+       xt_table_unlock(t);
        module_put(t->me);
  free:
        vfree(paddc);
@@ -1190,25 +1006,26 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
                }
                name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
 
-               t = try_then_request_module(find_table_lock(name),
+               t = try_then_request_module(xt_find_table_lock(NF_ARP, name),
                                            "arptable_%s", name);
                if (t && !IS_ERR(t)) {
                        struct arpt_getinfo info;
+                       struct xt_table_info *private = t->private;
 
                        info.valid_hooks = t->valid_hooks;
-                       memcpy(info.hook_entry, t->private->hook_entry,
+                       memcpy(info.hook_entry, private->hook_entry,
                               sizeof(info.hook_entry));
-                       memcpy(info.underflow, t->private->underflow,
+                       memcpy(info.underflow, private->underflow,
                               sizeof(info.underflow));
-                       info.num_entries = t->private->number;
-                       info.size = t->private->size;
+                       info.num_entries = private->number;
+                       info.size = private->size;
                        strcpy(info.name, name);
 
                        if (copy_to_user(user, &info, *len) != 0)
                                ret = -EFAULT;
                        else
                                ret = 0;
-                       up(&arpt_mutex);
+                       xt_table_unlock(t);
                        module_put(t->me);
                } else
                        ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1233,7 +1050,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
        }
 
        case ARPT_SO_GET_REVISION_TARGET: {
-               struct arpt_get_revision rev;
+               struct xt_get_revision rev;
 
                if (*len != sizeof(rev)) {
                        ret = -EINVAL;
@@ -1244,8 +1061,8 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
                        break;
                }
 
-               try_then_request_module(find_revision(rev.name, rev.revision,
-                                                     target_revfn, &ret),
+               try_then_request_module(xt_find_revision(NF_ARP, rev.name,
+                                                        rev.revision, 1, &ret),
                                        "arpt_%s", rev.name);
                break;
        }
@@ -1258,38 +1075,16 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
        return ret;
 }
 
-/* Registration hooks for targets. */
-int arpt_register_target(struct arpt_target *target)
-{
-       int ret;
-
-       ret = down_interruptible(&arpt_mutex);
-       if (ret != 0)
-               return ret;
-
-       list_add(&target->list, &arpt_target);
-       up(&arpt_mutex);
-
-       return ret;
-}
-
-void arpt_unregister_target(struct arpt_target *target)
-{
-       down(&arpt_mutex);
-       LIST_DELETE(&arpt_target, target);
-       up(&arpt_mutex);
-}
-
 int arpt_register_table(struct arpt_table *table,
                        const struct arpt_replace *repl)
 {
        int ret;
-       struct arpt_table_info *newinfo;
-       static struct arpt_table_info bootstrap
+       struct xt_table_info *newinfo;
+       static struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
 
-       newinfo = alloc_table_info(repl->size);
+       newinfo = xt_alloc_table_info(repl->size);
        if (!newinfo) {
                ret = -ENOMEM;
                return ret;
@@ -1304,60 +1099,33 @@ int arpt_register_table(struct arpt_table *table,
                              repl->num_entries,
                              repl->hook_entry,
                              repl->underflow);
+
        duprintf("arpt_register_table: translate table gives %d\n", ret);
        if (ret != 0) {
-               free_table_info(newinfo);
+               xt_free_table_info(newinfo);
                return ret;
        }
 
-       ret = down_interruptible(&arpt_mutex);
-       if (ret != 0) {
-               free_table_info(newinfo);
+       if (xt_register_table(table, &bootstrap, newinfo) != 0) {
+               xt_free_table_info(newinfo);
                return ret;
        }
 
-       /* Don't autoload: we'd eat our tail... */
-       if (list_named_find(&arpt_tables, table->name)) {
-               ret = -EEXIST;
-               goto free_unlock;
-       }
-
-       /* Simplifies replace_table code. */
-       table->private = &bootstrap;
-       if (!replace_table(table, 0, newinfo, &ret))
-               goto free_unlock;
-
-       duprintf("table->private->number = %u\n",
-                table->private->number);
-       
-       /* save number of initial entries */
-       table->private->initial_entries = table->private->number;
-
-       rwlock_init(&table->lock);
-       list_prepend(&arpt_tables, table);
-
- unlock:
-       up(&arpt_mutex);
-       return ret;
-
- free_unlock:
-       free_table_info(newinfo);
-       goto unlock;
+       return 0;
 }
 
 void arpt_unregister_table(struct arpt_table *table)
 {
+       struct xt_table_info *private;
        void *loc_cpu_entry;
 
-       down(&arpt_mutex);
-       LIST_DELETE(&arpt_tables, table);
-       up(&arpt_mutex);
+       private = xt_unregister_table(table);
 
        /* Decrease module usage counts and free resources */
-       loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
-       ARPT_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
+       ARPT_ENTRY_ITERATE(loc_cpu_entry, private->size,
                           cleanup_entry, NULL);
-       free_table_info(table->private);
+       xt_free_table_info(private);
 }
 
 /* The built-in targets: standard (NULL) and error. */
@@ -1380,52 +1148,15 @@ static struct nf_sockopt_ops arpt_sockopts = {
        .get            = do_arpt_get_ctl,
 };
 
-#ifdef CONFIG_PROC_FS
-static inline int print_name(const struct arpt_table *t,
-                            off_t start_offset, char *buffer, int length,
-                            off_t *pos, unsigned int *count)
-{
-       if ((*count)++ >= start_offset) {
-               unsigned int namelen;
-
-               namelen = sprintf(buffer + *pos, "%s\n", t->name);
-               if (*pos + namelen > length) {
-                       /* Stop iterating */
-                       return 1;
-               }
-               *pos += namelen;
-       }
-       return 0;
-}
-
-static int arpt_get_tables(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&arpt_mutex) != 0)
-               return 0;
-
-       LIST_FIND(&arpt_tables, print_name, struct arpt_table *,
-                 offset, buffer, length, &pos, &count);
-
-       up(&arpt_mutex);
-
-       /* `start' hack - see fs/proc/generic.c line ~105 */
-       *start=(char *)((unsigned long)count-offset);
-       return pos;
-}
-#endif /*CONFIG_PROC_FS*/
-
 static int __init init(void)
 {
        int ret;
 
+       xt_proto_init(NF_ARP);
+
        /* Noone else will be downing sem now, so we won't sleep */
-       down(&arpt_mutex);
-       list_append(&arpt_target, &arpt_standard_target);
-       list_append(&arpt_target, &arpt_error_target);
-       up(&arpt_mutex);
+       xt_register_target(NF_ARP, &arpt_standard_target);
+       xt_register_target(NF_ARP, &arpt_error_target);
 
        /* Register setsockopt */
        ret = nf_register_sockopt(&arpt_sockopts);
@@ -1434,19 +1165,6 @@ static int __init init(void)
                return ret;
        }
 
-#ifdef CONFIG_PROC_FS
-       {
-               struct proc_dir_entry *proc;
-
-               proc = proc_net_create("arp_tables_names", 0, arpt_get_tables);
-               if (!proc) {
-                       nf_unregister_sockopt(&arpt_sockopts);
-                       return -ENOMEM;
-               }
-               proc->owner = THIS_MODULE;
-       }
-#endif
-
        printk("arp_tables: (C) 2002 David S. Miller\n");
        return 0;
 }
@@ -1454,16 +1172,12 @@ static int __init init(void)
 static void __exit fini(void)
 {
        nf_unregister_sockopt(&arpt_sockopts);
-#ifdef CONFIG_PROC_FS
-       proc_net_remove("arp_tables_names");
-#endif
+       xt_proto_fini(NF_ARP);
 }
 
 EXPORT_SYMBOL(arpt_register_table);
 EXPORT_SYMBOL(arpt_unregister_table);
 EXPORT_SYMBOL(arpt_do_table);
-EXPORT_SYMBOL(arpt_register_target);
-EXPORT_SYMBOL(arpt_unregister_target);
 
 module_init(init);
 module_exit(fini);
index 3e592ec864826b1aef8aa2997d3410fb54d3af88..c97650a16a5b61607b1c0f7463fb43deb2ba3b79 100644 (file)
@@ -8,8 +8,9 @@ MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
 static unsigned int
-target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in,
-   const struct net_device *out, const void *targinfo, void *userinfo)
+target(struct sk_buff **pskb, const struct net_device *in,
+   const struct net_device *out, unsigned int hooknum, const void *targinfo,
+   void *userinfo)
 {
        const struct arpt_mangle *mangle = targinfo;
        struct arphdr *arp;
@@ -64,7 +65,7 @@ target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in,
 }
 
 static int
-checkentry(const char *tablename, const struct arpt_entry *e, void *targinfo,
+checkentry(const char *tablename, const void *e, void *targinfo,
    unsigned int targinfosize, unsigned int hook_mask)
 {
        const struct arpt_mangle *mangle = targinfo;
index 0d759f5a4ef0deb605f5463399e0ed773a43ab94..f6ab45f48681dca680d4fddfea7695907fc406cf 100644 (file)
@@ -145,6 +145,7 @@ static struct arpt_table packet_filter = {
        .lock           = RW_LOCK_UNLOCKED,
        .private        = NULL,
        .me             = THIS_MODULE,
+       .af             = NF_ARP,
 };
 
 /* The work comes in here from netfilter.c */
index 9dec1293f67aac7b4ee33156d13af9f3a08e6f5d..833fcb4be5e7df4d3519989c3ec8d3260b7e7a55 100644 (file)
@@ -944,7 +944,7 @@ module_exit(fini);
 
 /* Some modules need us, but don't depend directly on any symbol.
    They should call this. */
-void need_ip_conntrack(void)
+void need_conntrack(void)
 {
 }
 
@@ -962,7 +962,7 @@ EXPORT_SYMBOL(ip_ct_get_tuple);
 EXPORT_SYMBOL(invert_tuplepr);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
-EXPORT_SYMBOL(need_ip_conntrack);
+EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(ip_conntrack_helper_register);
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_iterate_cleanup);
index cb66b8bddeb3d63eb2ef23ee359a2491c6511c63..1de86282d23249c4181f92c80106c1dafcb81f8f 100644 (file)
@@ -95,6 +95,7 @@ static struct ipt_table nat_table = {
        .valid_hooks    = NAT_VALID_HOOKS,
        .lock           = RW_LOCK_UNLOCKED,
        .me             = THIS_MODULE,
+       .af             = AF_INET,
 };
 
 /* Source NAT */
@@ -168,7 +169,7 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
 }
 
 static int ipt_snat_checkentry(const char *tablename,
-                              const struct ipt_entry *e,
+                              const void *entry,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hook_mask)
@@ -201,7 +202,7 @@ static int ipt_snat_checkentry(const char *tablename,
 }
 
 static int ipt_dnat_checkentry(const char *tablename,
-                              const struct ipt_entry *e,
+                              const void *entry,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hook_mask)
index 8b8a1f00bbf4407e2a8f09d17831dae33fcd656f..ad438fb185b8943dfafde63c13fcbb405a5caf46 100644 (file)
@@ -364,7 +364,7 @@ static int init_or_cleanup(int init)
 {
        int ret = 0;
 
-       need_ip_conntrack();
+       need_conntrack();
 
        if (!init) goto cleanup;
 
index 877bc96d333684fae54d3af394d2e13aaf73d598..2371b2062c2d812468ad62f4fe19d4360e748f41 100644 (file)
@@ -2,7 +2,7 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
- * Copyright (C) 2000-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.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
@@ -11,6 +11,8 @@
  * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
  *     - increase module usage count as soon as we have rules inside
  *       a table
+ * 08 Oct 2005 Harald Welte <lafore@netfilter.org>
+ *     - Generalize into "x_tables" layer and "{ip,ip6,arp}_tables"
  */
 #include <linux/config.h>
 #include <linux/cache.h>
@@ -20,8 +22,6 @@
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
 #include <linux/icmp.h>
 #include <net/ip.h>
 #include <asm/uaccess.h>
@@ -30,6 +30,7 @@
 #include <linux/err.h>
 #include <linux/cpumask.h>
 
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 
 MODULE_LICENSE("GPL");
@@ -62,14 +63,6 @@ do {                                                         \
 #else
 #define IP_NF_ASSERT(x)
 #endif
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
-
-static DECLARE_MUTEX(ipt_mutex);
-
-/* Must have mutex */
-#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0)
-#define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ipt_mutex) != 0)
-#include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
 /* All the better to debug you with... */
@@ -86,36 +79,6 @@ static DECLARE_MUTEX(ipt_mutex);
 
    Hence the start of any table is given by get_table() below.  */
 
-/* The table itself */
-struct ipt_table_info
-{
-       /* Size per table */
-       unsigned int size;
-       /* Number of entries: FIXME. --RR */
-       unsigned int number;
-       /* Initial number of entries. Needed for module usage count */
-       unsigned int initial_entries;
-
-       /* Entry points and underflows */
-       unsigned int hook_entry[NF_IP_NUMHOOKS];
-       unsigned int underflow[NF_IP_NUMHOOKS];
-
-       /* ipt_entry tables: one per CPU */
-       void *entries[NR_CPUS];
-};
-
-static LIST_HEAD(ipt_target);
-static LIST_HEAD(ipt_match);
-static LIST_HEAD(ipt_tables);
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
-#if 0
-#define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
-#define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
-#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
-#endif
-
 /* Returns whether matches rule or not. */
 static inline int
 ip_packet_match(const struct iphdr *ip,
@@ -234,7 +197,8 @@ int do_match(struct ipt_entry_match *m,
             int *hotdrop)
 {
        /* Stop iteration if it doesn't match */
-       if (!m->u.kernel.match->match(skb, in, out, m->data, offset, hotdrop))
+       if (!m->u.kernel.match->match(skb, in, out, m->data, offset, 
+           skb->nh.iph->ihl*4, hotdrop))
                return 1;
        else
                return 0;
@@ -265,6 +229,7 @@ ipt_do_table(struct sk_buff **pskb,
        const char *indev, *outdev;
        void *table_base;
        struct ipt_entry *e, *back;
+       struct xt_table_info *private = table->private;
 
        /* Initialization */
        ip = (*pskb)->nh.iph;
@@ -281,24 +246,11 @@ ipt_do_table(struct sk_buff **pskb,
 
        read_lock_bh(&table->lock);
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
-       table_base = (void *)table->private->entries[smp_processor_id()];
-       e = get_entry(table_base, table->private->hook_entry[hook]);
-
-#ifdef CONFIG_NETFILTER_DEBUG
-       /* Check noone else using our table */
-       if (((struct ipt_entry *)table_base)->comefrom != 0xdead57ac
-           && ((struct ipt_entry *)table_base)->comefrom != 0xeeeeeeec) {
-               printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
-                      smp_processor_id(),
-                      table->name,
-                      &((struct ipt_entry *)table_base)->comefrom,
-                      ((struct ipt_entry *)table_base)->comefrom);
-       }
-       ((struct ipt_entry *)table_base)->comefrom = 0x57acc001;
-#endif
+       table_base = (void *)private->entries[smp_processor_id()];
+       e = get_entry(table_base, private->hook_entry[hook]);
 
        /* For return from builtin chain */
-       back = get_entry(table_base, table->private->underflow[hook]);
+       back = get_entry(table_base, private->underflow[hook]);
 
        do {
                IP_NF_ASSERT(e);
@@ -384,9 +336,6 @@ ipt_do_table(struct sk_buff **pskb,
                }
        } while (!hotdrop);
 
-#ifdef CONFIG_NETFILTER_DEBUG
-       ((struct ipt_entry *)table_base)->comefrom = 0xdead57ac;
-#endif
        read_unlock_bh(&table->lock);
 
 #ifdef DEBUG_ALLOW_ALL
@@ -398,145 +347,6 @@ ipt_do_table(struct sk_buff **pskb,
 #endif
 }
 
-/*
- * These are weird, but module loading must not be done with mutex
- * held (since they will register), and we have to have a single
- * function to use try_then_request_module().
- */
-
-/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-static inline struct ipt_table *find_table_lock(const char *name)
-{
-       struct ipt_table *t;
-
-       if (down_interruptible(&ipt_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(t, &ipt_tables, list)
-               if (strcmp(t->name, name) == 0 && try_module_get(t->me))
-                       return t;
-       up(&ipt_mutex);
-       return NULL;
-}
-
-/* Find match, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ipt_match *find_match(const char *name, u8 revision)
-{
-       struct ipt_match *m;
-       int err = 0;
-
-       if (down_interruptible(&ipt_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(m, &ipt_match, list) {
-               if (strcmp(m->name, name) == 0) {
-                       if (m->revision == revision) {
-                               if (try_module_get(m->me)) {
-                                       up(&ipt_mutex);
-                                       return m;
-                               }
-                       } else
-                               err = -EPROTOTYPE; /* Found something. */
-               }
-       }
-       up(&ipt_mutex);
-       return ERR_PTR(err);
-}
-
-/* Find target, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ipt_target *find_target(const char *name, u8 revision)
-{
-       struct ipt_target *t;
-       int err = 0;
-
-       if (down_interruptible(&ipt_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(t, &ipt_target, list) {
-               if (strcmp(t->name, name) == 0) {
-                       if (t->revision == revision) {
-                               if (try_module_get(t->me)) {
-                                       up(&ipt_mutex);
-                                       return t;
-                               }
-                       } else
-                               err = -EPROTOTYPE; /* Found something. */
-               }
-       }
-       up(&ipt_mutex);
-       return ERR_PTR(err);
-}
-
-struct ipt_target *ipt_find_target(const char *name, u8 revision)
-{
-       struct ipt_target *target;
-
-       target = try_then_request_module(find_target(name, revision),
-                                        "ipt_%s", name);
-       if (IS_ERR(target) || !target)
-               return NULL;
-       return target;
-}
-
-static int match_revfn(const char *name, u8 revision, int *bestp)
-{
-       struct ipt_match *m;
-       int have_rev = 0;
-
-       list_for_each_entry(m, &ipt_match, list) {
-               if (strcmp(m->name, name) == 0) {
-                       if (m->revision > *bestp)
-                               *bestp = m->revision;
-                       if (m->revision == revision)
-                               have_rev = 1;
-               }
-       }
-       return have_rev;
-}
-
-static int target_revfn(const char *name, u8 revision, int *bestp)
-{
-       struct ipt_target *t;
-       int have_rev = 0;
-
-       list_for_each_entry(t, &ipt_target, list) {
-               if (strcmp(t->name, name) == 0) {
-                       if (t->revision > *bestp)
-                               *bestp = t->revision;
-                       if (t->revision == revision)
-                               have_rev = 1;
-               }
-       }
-       return have_rev;
-}
-
-/* Returns true or false (if no such extension at all) */
-static inline int find_revision(const char *name, u8 revision,
-                               int (*revfn)(const char *, u8, int *),
-                               int *err)
-{
-       int have_rev, best = -1;
-
-       if (down_interruptible(&ipt_mutex) != 0) {
-               *err = -EINTR;
-               return 1;
-       }
-       have_rev = revfn(name, revision, &best);
-       up(&ipt_mutex);
-
-       /* Nothing at all?  Return 0 to try loading module. */
-       if (best == -1) {
-               *err = -ENOENT;
-               return 0;
-       }
-
-       *err = best;
-       if (!have_rev)
-               *err = -EPROTONOSUPPORT;
-       return 1;
-}
-
-
 /* All zeroes == unconditional rule. */
 static inline int
 unconditional(const struct ipt_ip *ip)
@@ -553,7 +363,7 @@ unconditional(const struct ipt_ip *ip)
 /* Figures out from what hook each rule can be called: returns 0 if
    there are loops.  Puts hook bitmask in comefrom. */
 static int
-mark_source_chains(struct ipt_table_info *newinfo,
+mark_source_chains(struct xt_table_info *newinfo,
                   unsigned int valid_hooks, void *entry0)
 {
        unsigned int hook;
@@ -699,7 +509,7 @@ check_match(struct ipt_entry_match *m,
 {
        struct ipt_match *match;
 
-       match = try_then_request_module(find_match(m->u.user.name,
+       match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
                                                   m->u.user.revision),
                                        "ipt_%s", m->u.user.name);
        if (IS_ERR(match) || !match) {
@@ -744,7 +554,8 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
                goto cleanup_matches;
 
        t = ipt_get_target(e);
-       target = try_then_request_module(find_target(t->u.user.name,
+       target = try_then_request_module(xt_find_target(AF_INET,
+                                                    t->u.user.name,
                                                     t->u.user.revision),
                                         "ipt_%s", t->u.user.name);
        if (IS_ERR(target) || !target) {
@@ -781,7 +592,7 @@ check_entry(struct ipt_entry *e, const char *name, unsigned int size,
 
 static inline int
 check_entry_size_and_hooks(struct ipt_entry *e,
-                          struct ipt_table_info *newinfo,
+                          struct xt_table_info *newinfo,
                           unsigned char *base,
                           unsigned char *limit,
                           const unsigned int *hook_entries,
@@ -815,7 +626,7 @@ check_entry_size_and_hooks(struct ipt_entry *e,
            < 0 (not IPT_RETURN). --RR */
 
        /* Clear counters and comefrom */
-       e->counters = ((struct ipt_counters) { 0, 0 });
+       e->counters = ((struct xt_counters) { 0, 0 });
        e->comefrom = 0;
 
        (*i)++;
@@ -845,7 +656,7 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i)
 static int
 translate_table(const char *name,
                unsigned int valid_hooks,
-               struct ipt_table_info *newinfo,
+               struct xt_table_info *newinfo,
                void *entry0,
                unsigned int size,
                unsigned int number,
@@ -922,48 +733,10 @@ translate_table(const char *name,
        return ret;
 }
 
-static struct ipt_table_info *
-replace_table(struct ipt_table *table,
-             unsigned int num_counters,
-             struct ipt_table_info *newinfo,
-             int *error)
-{
-       struct ipt_table_info *oldinfo;
-
-#ifdef CONFIG_NETFILTER_DEBUG
-       {
-               int cpu;
-
-               for_each_cpu(cpu) {
-                       struct ipt_entry *table_base = newinfo->entries[cpu];
-                       if (table_base)
-                               table_base->comefrom = 0xdead57ac;
-               }
-       }
-#endif
-
-       /* Do the substitution. */
-       write_lock_bh(&table->lock);
-       /* Check inside lock: is the old number correct? */
-       if (num_counters != table->private->number) {
-               duprintf("num_counters != table->private->number (%u/%u)\n",
-                        num_counters, table->private->number);
-               write_unlock_bh(&table->lock);
-               *error = -EAGAIN;
-               return NULL;
-       }
-       oldinfo = table->private;
-       table->private = newinfo;
-       newinfo->initial_entries = oldinfo->initial_entries;
-       write_unlock_bh(&table->lock);
-
-       return oldinfo;
-}
-
 /* Gets counters. */
 static inline int
 add_entry_to_counter(const struct ipt_entry *e,
-                    struct ipt_counters total[],
+                    struct xt_counters total[],
                     unsigned int *i)
 {
        ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -984,8 +757,8 @@ set_entry_to_counter(const struct ipt_entry *e,
 }
 
 static void
-get_counters(const struct ipt_table_info *t,
-            struct ipt_counters counters[])
+get_counters(const struct xt_table_info *t,
+            struct xt_counters counters[])
 {
        unsigned int cpu;
        unsigned int i;
@@ -1024,14 +797,15 @@ copy_entries_to_user(unsigned int total_size,
 {
        unsigned int off, num, countersize;
        struct ipt_entry *e;
-       struct ipt_counters *counters;
+       struct xt_counters *counters;
+       struct xt_table_info *private = table->private;
        int ret = 0;
        void *loc_cpu_entry;
 
        /* We need atomic snapshot of counters: rest doesn't change
           (other than comefrom, which userspace doesn't care
           about). */
-       countersize = sizeof(struct ipt_counters) * table->private->number;
+       countersize = sizeof(struct xt_counters) * private->number;
        counters = vmalloc_node(countersize, numa_node_id());
 
        if (counters == NULL)
@@ -1039,14 +813,14 @@ copy_entries_to_user(unsigned int total_size,
 
        /* First, sum counters... */
        write_lock_bh(&table->lock);
-       get_counters(table->private, counters);
+       get_counters(private, counters);
        write_unlock_bh(&table->lock);
 
        /* choose the copy that is on our node/cpu, ...
         * This choice is lazy (because current thread is
         * allowed to migrate to another cpu)
         */
-       loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
        /* ... then copy entire thing ... */
        if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
                ret = -EFAULT;
@@ -1108,74 +882,36 @@ get_entries(const struct ipt_get_entries *entries,
        int ret;
        struct ipt_table *t;
 
-       t = find_table_lock(entries->name);
+       t = xt_find_table_lock(AF_INET, entries->name);
        if (t && !IS_ERR(t)) {
+               struct xt_table_info *private = t->private;
                duprintf("t->private->number = %u\n",
-                        t->private->number);
-               if (entries->size == t->private->size)
-                       ret = copy_entries_to_user(t->private->size,
+                        private->number);
+               if (entries->size == private->size)
+                       ret = copy_entries_to_user(private->size,
                                                   t, uptr->entrytable);
                else {
                        duprintf("get_entries: I've got %u not %u!\n",
-                                t->private->size,
+                                private->size,
                                 entries->size);
                        ret = -EINVAL;
                }
                module_put(t->me);
-               up(&ipt_mutex);
+               xt_table_unlock(t);
        } else
                ret = t ? PTR_ERR(t) : -ENOENT;
 
        return ret;
 }
 
-static void free_table_info(struct ipt_table_info *info)
-{
-       int cpu;
-       for_each_cpu(cpu) {
-               if (info->size <= PAGE_SIZE)
-                       kfree(info->entries[cpu]);
-               else
-                       vfree(info->entries[cpu]);
-       }
-       kfree(info);
-}
-
-static struct ipt_table_info *alloc_table_info(unsigned int size)
-{
-       struct ipt_table_info *newinfo;
-       int cpu;
-
-       newinfo = kzalloc(sizeof(struct ipt_table_info), GFP_KERNEL);
-       if (!newinfo)
-               return NULL;
-
-       newinfo->size = size;
-
-       for_each_cpu(cpu) {
-               if (size <= PAGE_SIZE)
-                       newinfo->entries[cpu] = kmalloc_node(size,
-                               GFP_KERNEL,
-                               cpu_to_node(cpu));
-               else
-                       newinfo->entries[cpu] = vmalloc_node(size, cpu_to_node(cpu));
-               if (newinfo->entries[cpu] == 0) {
-                       free_table_info(newinfo);
-                       return NULL;
-               }
-       }
-
-       return newinfo;
-}
-
 static int
 do_replace(void __user *user, unsigned int len)
 {
        int ret;
        struct ipt_replace tmp;
        struct ipt_table *t;
-       struct ipt_table_info *newinfo, *oldinfo;
-       struct ipt_counters *counters;
+       struct xt_table_info *newinfo, *oldinfo;
+       struct xt_counters *counters;
        void *loc_cpu_entry, *loc_cpu_old_entry;
 
        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
@@ -1185,11 +921,7 @@ do_replace(void __user *user, unsigned int len)
        if (len != sizeof(tmp) + tmp.size)
                return -ENOPROTOOPT;
 
-       /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-       if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
-               return -ENOMEM;
-
-       newinfo = alloc_table_info(tmp.size);
+       newinfo = xt_alloc_table_info(tmp.size);
        if (!newinfo)
                return -ENOMEM;
 
@@ -1201,7 +933,7 @@ do_replace(void __user *user, unsigned int len)
                goto free_newinfo;
        }
 
-       counters = vmalloc(tmp.num_counters * sizeof(struct ipt_counters));
+       counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
        if (!counters) {
                ret = -ENOMEM;
                goto free_newinfo;
@@ -1215,7 +947,7 @@ do_replace(void __user *user, unsigned int len)
 
        duprintf("ip_tables: Translated table\n");
 
-       t = try_then_request_module(find_table_lock(tmp.name),
+       t = try_then_request_module(xt_find_table_lock(AF_INET, tmp.name),
                                    "iptable_%s", tmp.name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1230,7 +962,7 @@ do_replace(void __user *user, unsigned int len)
                goto put_module;
        }
 
-       oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
+       oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
        if (!oldinfo)
                goto put_module;
 
@@ -1249,23 +981,23 @@ do_replace(void __user *user, unsigned int len)
        /* Decrease module usage counts and free resource */
        loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
        IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
-       free_table_info(oldinfo);
+       xt_free_table_info(oldinfo);
        if (copy_to_user(tmp.counters, counters,
-                        sizeof(struct ipt_counters) * tmp.num_counters) != 0)
+                        sizeof(struct xt_counters) * tmp.num_counters) != 0)
                ret = -EFAULT;
        vfree(counters);
-       up(&ipt_mutex);
+       xt_table_unlock(t);
        return ret;
 
  put_module:
        module_put(t->me);
-       up(&ipt_mutex);
+       xt_table_unlock(t);
  free_newinfo_counters_untrans:
        IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
  free_newinfo_counters:
        vfree(counters);
  free_newinfo:
-       free_table_info(newinfo);
+       xt_free_table_info(newinfo);
        return ret;
 }
 
@@ -1273,7 +1005,7 @@ do_replace(void __user *user, unsigned int len)
  * and everything is OK. */
 static inline int
 add_counter_to_entry(struct ipt_entry *e,
-                    const struct ipt_counters addme[],
+                    const struct xt_counters addme[],
                     unsigned int *i)
 {
 #if 0
@@ -1295,15 +1027,16 @@ static int
 do_add_counters(void __user *user, unsigned int len)
 {
        unsigned int i;
-       struct ipt_counters_info tmp, *paddc;
+       struct xt_counters_info tmp, *paddc;
        struct ipt_table *t;
+       struct xt_table_info *private;
        int ret = 0;
        void *loc_cpu_entry;
 
        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
                return -EFAULT;
 
-       if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ipt_counters))
+       if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
                return -EINVAL;
 
        paddc = vmalloc_node(len, numa_node_id());
@@ -1315,29 +1048,30 @@ do_add_counters(void __user *user, unsigned int len)
                goto free;
        }
 
-       t = find_table_lock(tmp.name);
+       t = xt_find_table_lock(AF_INET, tmp.name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
        }
 
        write_lock_bh(&t->lock);
-       if (t->private->number != paddc->num_counters) {
+       private = t->private;
+       if (private->number != paddc->num_counters) {
                ret = -EINVAL;
                goto unlock_up_free;
        }
 
        i = 0;
        /* Choose the copy that is on our node */
-       loc_cpu_entry = t->private->entries[raw_smp_processor_id()];
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
        IPT_ENTRY_ITERATE(loc_cpu_entry,
-                         t->private->size,
+                         private->size,
                          add_counter_to_entry,
                          paddc->counters,
                          &i);
  unlock_up_free:
        write_unlock_bh(&t->lock);
-       up(&ipt_mutex);
+       xt_table_unlock(t);
        module_put(t->me);
  free:
        vfree(paddc);
@@ -1396,25 +1130,26 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                }
                name[IPT_TABLE_MAXNAMELEN-1] = '\0';
 
-               t = try_then_request_module(find_table_lock(name),
+               t = try_then_request_module(xt_find_table_lock(AF_INET, name),
                                            "iptable_%s", name);
                if (t && !IS_ERR(t)) {
                        struct ipt_getinfo info;
+                       struct xt_table_info *private = t->private;
 
                        info.valid_hooks = t->valid_hooks;
-                       memcpy(info.hook_entry, t->private->hook_entry,
+                       memcpy(info.hook_entry, private->hook_entry,
                               sizeof(info.hook_entry));
-                       memcpy(info.underflow, t->private->underflow,
+                       memcpy(info.underflow, private->underflow,
                               sizeof(info.underflow));
-                       info.num_entries = t->private->number;
-                       info.size = t->private->size;
+                       info.num_entries = private->number;
+                       info.size = private->size;
                        memcpy(info.name, name, sizeof(info.name));
 
                        if (copy_to_user(user, &info, *len) != 0)
                                ret = -EFAULT;
                        else
                                ret = 0;
-                       up(&ipt_mutex);
+                       xt_table_unlock(t);
                        module_put(t->me);
                } else
                        ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1441,7 +1176,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        case IPT_SO_GET_REVISION_MATCH:
        case IPT_SO_GET_REVISION_TARGET: {
                struct ipt_get_revision rev;
-               int (*revfn)(const char *, u8, int *);
+               int target;
 
                if (*len != sizeof(rev)) {
                        ret = -EINVAL;
@@ -1453,12 +1188,13 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                }
 
                if (cmd == IPT_SO_GET_REVISION_TARGET)
-                       revfn = target_revfn;
+                       target = 1;
                else
-                       revfn = match_revfn;
+                       target = 0;
 
-               try_then_request_module(find_revision(rev.name, rev.revision,
-                                                     revfn, &ret),
+               try_then_request_module(xt_find_revision(AF_INET, rev.name,
+                                                        rev.revision,
+                                                        target, &ret),
                                        "ipt_%s", rev.name);
                break;
        }
@@ -1471,60 +1207,15 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-/* Registration hooks for targets. */
-int
-ipt_register_target(struct ipt_target *target)
+int ipt_register_table(struct xt_table *table, const struct ipt_replace *repl)
 {
        int ret;
-
-       ret = down_interruptible(&ipt_mutex);
-       if (ret != 0)
-               return ret;
-       list_add(&target->list, &ipt_target);
-       up(&ipt_mutex);
-       return ret;
-}
-
-void
-ipt_unregister_target(struct ipt_target *target)
-{
-       down(&ipt_mutex);
-       LIST_DELETE(&ipt_target, target);
-       up(&ipt_mutex);
-}
-
-int
-ipt_register_match(struct ipt_match *match)
-{
-       int ret;
-
-       ret = down_interruptible(&ipt_mutex);
-       if (ret != 0)
-               return ret;
-
-       list_add(&match->list, &ipt_match);
-       up(&ipt_mutex);
-
-       return ret;
-}
-
-void
-ipt_unregister_match(struct ipt_match *match)
-{
-       down(&ipt_mutex);
-       LIST_DELETE(&ipt_match, match);
-       up(&ipt_mutex);
-}
-
-int ipt_register_table(struct ipt_table *table, const struct ipt_replace *repl)
-{
-       int ret;
-       struct ipt_table_info *newinfo;
-       static struct ipt_table_info bootstrap
+       struct xt_table_info *newinfo;
+       static struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
 
-       newinfo = alloc_table_info(repl->size);
+       newinfo = xt_alloc_table_info(repl->size);
        if (!newinfo)
                return -ENOMEM;
 
@@ -1540,246 +1231,29 @@ int ipt_register_table(struct ipt_table *table, const struct ipt_replace *repl)
                              repl->hook_entry,
                              repl->underflow);
        if (ret != 0) {
-               free_table_info(newinfo);
+               xt_free_table_info(newinfo);
                return ret;
        }
 
-       ret = down_interruptible(&ipt_mutex);
-       if (ret != 0) {
-               free_table_info(newinfo);
+       if (xt_register_table(table, &bootstrap, newinfo) != 0) {
+               xt_free_table_info(newinfo);
                return ret;
        }
 
-       /* Don't autoload: we'd eat our tail... */
-       if (list_named_find(&ipt_tables, table->name)) {
-               ret = -EEXIST;
-               goto free_unlock;
-       }
-
-       /* Simplifies replace_table code. */
-       table->private = &bootstrap;
-       if (!replace_table(table, 0, newinfo, &ret))
-               goto free_unlock;
-
-       duprintf("table->private->number = %u\n",
-                table->private->number);
-       
-       /* save number of initial entries */
-       table->private->initial_entries = table->private->number;
-
-       rwlock_init(&table->lock);
-       list_prepend(&ipt_tables, table);
-
- unlock:
-       up(&ipt_mutex);
-       return ret;
-
- free_unlock:
-       free_table_info(newinfo);
-       goto unlock;
+       return 0;
 }
 
 void ipt_unregister_table(struct ipt_table *table)
 {
+       struct xt_table_info *private;
        void *loc_cpu_entry;
 
-       down(&ipt_mutex);
-       LIST_DELETE(&ipt_tables, table);
-       up(&ipt_mutex);
+       private = xt_unregister_table(table);
 
        /* Decrease module usage counts and free resources */
-       loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
-       IPT_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
-                         cleanup_entry, NULL);
-       free_table_info(table->private);
-}
-
-/* Returns 1 if the port is matched by the range, 0 otherwise */
-static inline int
-port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
-{
-       int ret;
-
-       ret = (port >= min && port <= max) ^ invert;
-       return ret;
-}
-
-static int
-tcp_find_option(u_int8_t option,
-               const struct sk_buff *skb,
-               unsigned int optlen,
-               int invert,
-               int *hotdrop)
-{
-       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-       u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
-       unsigned int i;
-
-       duprintf("tcp_match: finding option\n");
-
-       if (!optlen)
-               return invert;
-
-       /* If we don't have the whole header, drop packet. */
-       op = skb_header_pointer(skb,
-                               skb->nh.iph->ihl*4 + sizeof(struct tcphdr),
-                               optlen, _opt);
-       if (op == NULL) {
-               *hotdrop = 1;
-               return 0;
-       }
-
-       for (i = 0; i < optlen; ) {
-               if (op[i] == option) return !invert;
-               if (op[i] < 2) i++;
-               else i += op[i+1]?:1;
-       }
-
-       return invert;
-}
-
-static int
-tcp_match(const struct sk_buff *skb,
-         const struct net_device *in,
-         const struct net_device *out,
-         const void *matchinfo,
-         int offset,
-         int *hotdrop)
-{
-       struct tcphdr _tcph, *th;
-       const struct ipt_tcp *tcpinfo = matchinfo;
-
-       if (offset) {
-               /* To quote Alan:
-
-                  Don't allow a fragment of TCP 8 bytes in. Nobody normal
-                  causes this. Its a cracker trying to break in by doing a
-                  flag overwrite to pass the direction checks.
-               */
-               if (offset == 1) {
-                       duprintf("Dropping evil TCP offset=1 frag.\n");
-                       *hotdrop = 1;
-               }
-               /* Must not be a fragment. */
-               return 0;
-       }
-
-#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
-
-       th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-                               sizeof(_tcph), &_tcph);
-       if (th == NULL) {
-               /* We've been asked to examine this packet, and we
-                  can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil TCP offset=0 tinygram.\n");
-               *hotdrop = 1;
-               return 0;
-       }
-
-       if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
-                       ntohs(th->source),
-                       !!(tcpinfo->invflags & IPT_TCP_INV_SRCPT)))
-               return 0;
-       if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
-                       ntohs(th->dest),
-                       !!(tcpinfo->invflags & IPT_TCP_INV_DSTPT)))
-               return 0;
-       if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
-                     == tcpinfo->flg_cmp,
-                     IPT_TCP_INV_FLAGS))
-               return 0;
-       if (tcpinfo->option) {
-               if (th->doff * 4 < sizeof(_tcph)) {
-                       *hotdrop = 1;
-                       return 0;
-               }
-               if (!tcp_find_option(tcpinfo->option, skb,
-                                    th->doff*4 - sizeof(_tcph),
-                                    tcpinfo->invflags & IPT_TCP_INV_OPTION,
-                                    hotdrop))
-                       return 0;
-       }
-       return 1;
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-tcp_checkentry(const char *tablename,
-              const struct ipt_ip *ip,
-              void *matchinfo,
-              unsigned int matchsize,
-              unsigned int hook_mask)
-{
-       const struct ipt_tcp *tcpinfo = matchinfo;
-
-       /* Must specify proto == TCP, and no unknown invflags */
-       return ip->proto == IPPROTO_TCP
-               && !(ip->invflags & IPT_INV_PROTO)
-               && matchsize == IPT_ALIGN(sizeof(struct ipt_tcp))
-               && !(tcpinfo->invflags & ~IPT_TCP_INV_MASK);
-}
-
-static int
-udp_match(const struct sk_buff *skb,
-         const struct net_device *in,
-         const struct net_device *out,
-         const void *matchinfo,
-         int offset,
-         int *hotdrop)
-{
-       struct udphdr _udph, *uh;
-       const struct ipt_udp *udpinfo = matchinfo;
-
-       /* Must not be a fragment. */
-       if (offset)
-               return 0;
-
-       uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-                               sizeof(_udph), &_udph);
-       if (uh == NULL) {
-               /* We've been asked to examine this packet, and we
-                  can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil UDP tinygram.\n");
-               *hotdrop = 1;
-               return 0;
-       }
-
-       return port_match(udpinfo->spts[0], udpinfo->spts[1],
-                         ntohs(uh->source),
-                         !!(udpinfo->invflags & IPT_UDP_INV_SRCPT))
-               && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
-                             ntohs(uh->dest),
-                             !!(udpinfo->invflags & IPT_UDP_INV_DSTPT));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-udp_checkentry(const char *tablename,
-              const struct ipt_ip *ip,
-              void *matchinfo,
-              unsigned int matchinfosize,
-              unsigned int hook_mask)
-{
-       const struct ipt_udp *udpinfo = matchinfo;
-
-       /* Must specify proto == UDP, and no unknown invflags */
-       if (ip->proto != IPPROTO_UDP || (ip->invflags & IPT_INV_PROTO)) {
-               duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
-                        IPPROTO_UDP);
-               return 0;
-       }
-       if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_udp))) {
-               duprintf("ipt_udp: matchsize %u != %u\n",
-                        matchinfosize, IPT_ALIGN(sizeof(struct ipt_udp)));
-               return 0;
-       }
-       if (udpinfo->invflags & ~IPT_UDP_INV_MASK) {
-               duprintf("ipt_udp: unknown flags %X\n",
-                        udpinfo->invflags);
-               return 0;
-       }
-
-       return 1;
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
+       IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
+       xt_free_table_info(private);
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -1798,6 +1272,7 @@ icmp_match(const struct sk_buff *skb,
           const struct net_device *out,
           const void *matchinfo,
           int offset,
+          unsigned int protoff,
           int *hotdrop)
 {
        struct icmphdr _icmph, *ic;
@@ -1807,8 +1282,7 @@ icmp_match(const struct sk_buff *skb,
        if (offset)
                return 0;
 
-       ic = skb_header_pointer(skb, skb->nh.iph->ihl*4,
-                               sizeof(_icmph), &_icmph);
+       ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
        if (ic == NULL) {
                /* We've been asked to examine this packet, and we
                 * can't.  Hence, no choice but to drop.
@@ -1828,11 +1302,12 @@ icmp_match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 icmp_checkentry(const char *tablename,
-          const struct ipt_ip *ip,
+          const void *info,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
+       const struct ipt_ip *ip = info;
        const struct ipt_icmp *icmpinfo = matchinfo;
 
        /* Must specify proto == ICMP, and no unknown invflags */
@@ -1862,123 +1337,22 @@ static struct nf_sockopt_ops ipt_sockopts = {
        .get            = do_ipt_get_ctl,
 };
 
-static struct ipt_match tcp_matchstruct = {
-       .name           = "tcp",
-       .match          = &tcp_match,
-       .checkentry     = &tcp_checkentry,
-};
-
-static struct ipt_match udp_matchstruct = {
-       .name           = "udp",
-       .match          = &udp_match,
-       .checkentry     = &udp_checkentry,
-};
-
 static struct ipt_match icmp_matchstruct = {
        .name           = "icmp",
        .match          = &icmp_match,
        .checkentry     = &icmp_checkentry,
 };
 
-#ifdef CONFIG_PROC_FS
-static inline int print_name(const char *i,
-                            off_t start_offset, char *buffer, int length,
-                            off_t *pos, unsigned int *count)
-{
-       if ((*count)++ >= start_offset) {
-               unsigned int namelen;
-
-               namelen = sprintf(buffer + *pos, "%s\n",
-                                 i + sizeof(struct list_head));
-               if (*pos + namelen > length) {
-                       /* Stop iterating */
-                       return 1;
-               }
-               *pos += namelen;
-       }
-       return 0;
-}
-
-static inline int print_target(const struct ipt_target *t,
-                               off_t start_offset, char *buffer, int length,
-                               off_t *pos, unsigned int *count)
-{
-       if (t == &ipt_standard_target || t == &ipt_error_target)
-               return 0;
-       return print_name((char *)t, start_offset, buffer, length, pos, count);
-}
-
-static int ipt_get_tables(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&ipt_mutex) != 0)
-               return 0;
-
-       LIST_FIND(&ipt_tables, print_name, void *,
-                 offset, buffer, length, &pos, &count);
-
-       up(&ipt_mutex);
-
-       /* `start' hack - see fs/proc/generic.c line ~105 */
-       *start=(char *)((unsigned long)count-offset);
-       return pos;
-}
-
-static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&ipt_mutex) != 0)
-               return 0;
-
-       LIST_FIND(&ipt_target, print_target, struct ipt_target *,
-                 offset, buffer, length, &pos, &count);
-       
-       up(&ipt_mutex);
-
-       *start = (char *)((unsigned long)count - offset);
-       return pos;
-}
-
-static int ipt_get_matches(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&ipt_mutex) != 0)
-               return 0;
-       
-       LIST_FIND(&ipt_match, print_name, void *,
-                 offset, buffer, length, &pos, &count);
-
-       up(&ipt_mutex);
-
-       *start = (char *)((unsigned long)count - offset);
-       return pos;
-}
-
-static const struct { char *name; get_info_t *get_info; } ipt_proc_entry[] =
-{ { "ip_tables_names", ipt_get_tables },
-  { "ip_tables_targets", ipt_get_targets },
-  { "ip_tables_matches", ipt_get_matches },
-  { NULL, NULL} };
-#endif /*CONFIG_PROC_FS*/
-
 static int __init init(void)
 {
        int ret;
 
+       xt_proto_init(AF_INET);
+
        /* Noone else will be downing sem now, so we won't sleep */
-       down(&ipt_mutex);
-       list_append(&ipt_target, &ipt_standard_target);
-       list_append(&ipt_target, &ipt_error_target);
-       list_append(&ipt_match, &tcp_matchstruct);
-       list_append(&ipt_match, &udp_matchstruct);
-       list_append(&ipt_match, &icmp_matchstruct);
-       up(&ipt_mutex);
+       xt_register_target(AF_INET, &ipt_standard_target);
+       xt_register_target(AF_INET, &ipt_error_target);
+       xt_register_match(AF_INET, &icmp_matchstruct);
 
        /* Register setsockopt */
        ret = nf_register_sockopt(&ipt_sockopts);
@@ -1987,49 +1361,23 @@ static int __init init(void)
                return ret;
        }
 
-#ifdef CONFIG_PROC_FS
-       {
-       struct proc_dir_entry *proc;
-       int i;
-
-       for (i = 0; ipt_proc_entry[i].name; i++) {
-               proc = proc_net_create(ipt_proc_entry[i].name, 0,
-                                      ipt_proc_entry[i].get_info);
-               if (!proc) {
-                       while (--i >= 0)
-                               proc_net_remove(ipt_proc_entry[i].name);
-                       nf_unregister_sockopt(&ipt_sockopts);
-                       return -ENOMEM;
-               }
-               proc->owner = THIS_MODULE;
-       }
-       }
-#endif
-
-       printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
+       printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
        return 0;
 }
 
 static void __exit fini(void)
 {
        nf_unregister_sockopt(&ipt_sockopts);
-#ifdef CONFIG_PROC_FS
-       {
-       int i;
-       for (i = 0; ipt_proc_entry[i].name; i++)
-               proc_net_remove(ipt_proc_entry[i].name);
-       }
-#endif
+
+       xt_unregister_match(AF_INET, &icmp_matchstruct);
+       xt_unregister_target(AF_INET, &ipt_error_target);
+       xt_unregister_target(AF_INET, &ipt_standard_target);
+
+       xt_proto_fini(AF_INET);
 }
 
 EXPORT_SYMBOL(ipt_register_table);
 EXPORT_SYMBOL(ipt_unregister_table);
-EXPORT_SYMBOL(ipt_register_match);
-EXPORT_SYMBOL(ipt_unregister_match);
 EXPORT_SYMBOL(ipt_do_table);
-EXPORT_SYMBOL(ipt_register_target);
-EXPORT_SYMBOL(ipt_unregister_target);
-EXPORT_SYMBOL(ipt_find_target);
-
 module_init(init);
 module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_CLASSIFY.c b/net/ipv4/netfilter/ipt_CLASSIFY.c
deleted file mode 100644 (file)
index dab78d8..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * This is a module which is used for setting the skb->priority field
- * of an skb for qdisc classification.
- */
-
-/* (C) 2001-2002 Patrick McHardy <kaber@trash.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/module.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_CLASSIFY.h>
-
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("iptables qdisc classification target module");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-       const struct ipt_classify_target_info *clinfo = targinfo;
-
-       if((*pskb)->priority != clinfo->priority) 
-               (*pskb)->priority = clinfo->priority;
-
-       return IPT_CONTINUE;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_classify_target_info))){
-               printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_classify_target_info)));
-               return 0;
-       }
-       
-       if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
-                         (1 << NF_IP_POST_ROUTING))) {
-               printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD "
-                               "and POST_ROUTING.\n");
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_ERR "CLASSIFY: can only be called from "
-                               "\"mangle\" table, not \"%s\".\n",
-                               tablename);
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_target ipt_classify_reg = { 
-       .name           = "CLASSIFY", 
-       .target         = target,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_target(&ipt_classify_reg);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_target(&ipt_classify_reg);
-}
-
-module_init(init);
-module_exit(fini);
index 45c52d8f4d99750c0407b8d8cd3510792e85ef3f..d9bc971f03afd677907bf9651e2551f227f34e18 100644 (file)
@@ -379,12 +379,13 @@ target(struct sk_buff **pskb,
 
 static int
 checkentry(const char *tablename,
-          const struct ipt_entry *e,
+          const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
        struct ipt_clusterip_tgt_info *cipinfo = targinfo;
+       const struct ipt_entry *e = e_void;
 
        struct clusterip_config *config;
 
diff --git a/net/ipv4/netfilter/ipt_CONNMARK.c b/net/ipv4/netfilter/ipt_CONNMARK.c
deleted file mode 100644 (file)
index 8acac5a..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* This kernel module is used to modify the connection mark values, or
- * to optionally restore the skb nfmark from the connection mark
- *
- * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
- * by Henrik Nordstrom <hno@marasystems.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/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
-MODULE_DESCRIPTION("IP tables CONNMARK matching module");
-MODULE_LICENSE("GPL");
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-       const struct ipt_connmark_target_info *markinfo = targinfo;
-       u_int32_t diff;
-       u_int32_t nfmark;
-       u_int32_t newmark;
-       u_int32_t ctinfo;
-       u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
-
-       if (ctmark) {
-           switch(markinfo->mode) {
-           case IPT_CONNMARK_SET:
-               newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
-               if (newmark != *ctmark)
-                   *ctmark = newmark;
-               break;
-           case IPT_CONNMARK_SAVE:
-               newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
-               if (*ctmark != newmark)
-                   *ctmark = newmark;
-               break;
-           case IPT_CONNMARK_RESTORE:
-               nfmark = (*pskb)->nfmark;
-               diff = (*ctmark ^ nfmark) & markinfo->mask;
-               if (diff != 0)
-                   (*pskb)->nfmark = nfmark ^ diff;
-               break;
-           }
-       }
-
-       return IPT_CONTINUE;
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ipt_entry *e,
-          void *targinfo,
-          unsigned int targinfosize,
-          unsigned int hook_mask)
-{
-       struct ipt_connmark_target_info *matchinfo = targinfo;
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
-               printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
-               return 0;
-       }
-
-       if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
-           if (strcmp(tablename, "mangle") != 0) {
-                   printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-                   return 0;
-           }
-       }
-
-       if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
-               printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_target ipt_connmark_reg = {
-       .name = "CONNMARK",
-       .target = &target,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       need_ip_conntrack();
-       return ipt_register_target(&ipt_connmark_reg);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_target(&ipt_connmark_reg);
-}
-
-module_init(init);
-module_exit(fini);
index 6e319570a28caf01107dff4e825f6844aa52d992..898cdf79ce18258eb75dc073ee5e228c81a21b60 100644 (file)
@@ -57,7 +57,7 @@ target(struct sk_buff **pskb,
 
 static int
 checkentry(const char *tablename,
-          const struct ipt_entry *e,
+          const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
index a1319693f648c2beba63fea33070c8c79fe04fef..706445426a6dfc4096d97e76d33cfe27a74ea665 100644 (file)
@@ -113,12 +113,13 @@ target(struct sk_buff **pskb,
 
 static int
 checkentry(const char *tablename,
-          const struct ipt_entry *e,
+          const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
 {
        const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
+       const struct ipt_entry *e = e_void;
 
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
                printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
index 30be0f1dae370f6212de7955a972e87272854bef..6606ddb66a29e6ea0044c24ce596bb9767aae424 100644 (file)
@@ -431,7 +431,7 @@ ipt_log_target(struct sk_buff **pskb,
 }
 
 static int ipt_log_checkentry(const char *tablename,
-                             const struct ipt_entry *e,
+                             const void *e,
                              void *targinfo,
                              unsigned int targinfosize,
                              unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_MARK.c b/net/ipv4/netfilter/ipt_MARK.c
deleted file mode 100644 (file)
index 52b4f2c..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/* This is a module which is used for setting the NFMARK field of an skb. */
-
-/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *
- * 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/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_MARK.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables MARK modification module");
-
-static unsigned int
-target_v0(struct sk_buff **pskb,
-         const struct net_device *in,
-         const struct net_device *out,
-         unsigned int hooknum,
-         const void *targinfo,
-         void *userinfo)
-{
-       const struct ipt_mark_target_info *markinfo = targinfo;
-
-       if((*pskb)->nfmark != markinfo->mark)
-               (*pskb)->nfmark = markinfo->mark;
-
-       return IPT_CONTINUE;
-}
-
-static unsigned int
-target_v1(struct sk_buff **pskb,
-         const struct net_device *in,
-         const struct net_device *out,
-         unsigned int hooknum,
-         const void *targinfo,
-         void *userinfo)
-{
-       const struct ipt_mark_target_info_v1 *markinfo = targinfo;
-       int mark = 0;
-
-       switch (markinfo->mode) {
-       case IPT_MARK_SET:
-               mark = markinfo->mark;
-               break;
-               
-       case IPT_MARK_AND:
-               mark = (*pskb)->nfmark & markinfo->mark;
-               break;
-               
-       case IPT_MARK_OR:
-               mark = (*pskb)->nfmark | markinfo->mark;
-               break;
-       }
-
-       if((*pskb)->nfmark != mark)
-               (*pskb)->nfmark = mark;
-
-       return IPT_CONTINUE;
-}
-
-
-static int
-checkentry_v0(const char *tablename,
-             const struct ipt_entry *e,
-             void *targinfo,
-             unsigned int targinfosize,
-             unsigned int hook_mask)
-{
-       struct ipt_mark_target_info *markinfo = targinfo;
-
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info))) {
-               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_mark_target_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
-       if (markinfo->mark > 0xffffffff) {
-               printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static int
-checkentry_v1(const char *tablename,
-             const struct ipt_entry *e,
-             void *targinfo,
-             unsigned int targinfosize,
-             unsigned int hook_mask)
-{
-       struct ipt_mark_target_info_v1 *markinfo = targinfo;
-
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1))){
-               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_mark_target_info_v1)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
-       if (markinfo->mode != IPT_MARK_SET
-           && markinfo->mode != IPT_MARK_AND
-           && markinfo->mode != IPT_MARK_OR) {
-               printk(KERN_WARNING "MARK: unknown mode %u\n",
-                      markinfo->mode);
-               return 0;
-       }
-
-       if (markinfo->mark > 0xffffffff) {
-               printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_target ipt_mark_reg_v0 = {
-       .name           = "MARK",
-       .target         = target_v0,
-       .checkentry     = checkentry_v0,
-       .me             = THIS_MODULE,
-       .revision       = 0,
-};
-
-static struct ipt_target ipt_mark_reg_v1 = {
-       .name           = "MARK",
-       .target         = target_v1,
-       .checkentry     = checkentry_v1,
-       .me             = THIS_MODULE,
-       .revision       = 1,
-};
-
-static int __init init(void)
-{
-       int err;
-
-       err = ipt_register_target(&ipt_mark_reg_v0);
-       if (!err) {
-               err = ipt_register_target(&ipt_mark_reg_v1);
-               if (err)
-                       ipt_unregister_target(&ipt_mark_reg_v0);
-       }
-       return err;
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_target(&ipt_mark_reg_v0);
-       ipt_unregister_target(&ipt_mark_reg_v1);
-}
-
-module_init(init);
-module_exit(fini);
index 27860510ca6dacb4464f65352b5f4e9c917c9921..12c56d3343ca3b7d38bd5153f21e7a2b23eb0fd1 100644 (file)
@@ -40,7 +40,7 @@ static DEFINE_RWLOCK(masq_lock);
 /* FIXME: Multiple targets. --RR */
 static int
 masquerade_check(const char *tablename,
-                const struct ipt_entry *e,
+                const void *e,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
index e6e7b6095363db60b760b93196c5d289a3796da0..b074467fe67b642c0345c152c989363dd617c9bc 100644 (file)
@@ -31,7 +31,7 @@ MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target");
 
 static int
 check(const char *tablename,
-      const struct ipt_entry *e,
+      const void *e,
       void *targinfo,
       unsigned int targinfosize,
       unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_NFQUEUE.c b/net/ipv4/netfilter/ipt_NFQUEUE.c
deleted file mode 100644 (file)
index 3cedc9b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* iptables module for using new netfilter netlink queue
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
-
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("iptables NFQUEUE target");
-MODULE_LICENSE("GPL");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-       const struct ipt_NFQ_info *tinfo = targinfo;
-
-       return NF_QUEUE_NR(tinfo->queuenum);
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ipt_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_NFQ_info))) {
-               printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IPT_ALIGN(sizeof(struct ipt_NFQ_info)));
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_target ipt_NFQ_reg = {
-       .name           = "NFQUEUE",
-       .target         = target,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_target(&ipt_NFQ_reg);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_target(&ipt_NFQ_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_NOTRACK.c b/net/ipv4/netfilter/ipt_NOTRACK.c
deleted file mode 100644 (file)
index e3c69d0..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* This is a module which is used for setting up fake conntracks
- * on packets so that they are not seen by the conntrack/NAT code.
- */
-#include <linux/module.h>
-#include <linux/skbuff.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-       /* Previously seen (loopback)? Ignore. */
-       if ((*pskb)->nfct != NULL)
-               return IPT_CONTINUE;
-
-       /* Attach fake conntrack entry. 
-          If there is a real ct entry correspondig to this packet, 
-          it'll hang aroun till timing out. We don't deal with it
-          for performance reasons. JK */
-       nf_ct_untrack(*pskb);
-       (*pskb)->nfctinfo = IP_CT_NEW;
-       nf_conntrack_get((*pskb)->nfct);
-
-       return IPT_CONTINUE;
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ipt_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != 0) {
-               printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
-                      targinfosize);
-               return 0;
-       }
-
-       if (strcmp(tablename, "raw") != 0) {
-               printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_target ipt_notrack_reg = { 
-       .name = "NOTRACK", 
-       .target = target, 
-       .checkentry = checkentry,
-       .me = THIS_MODULE 
-};
-
-static int __init init(void)
-{
-       if (ipt_register_target(&ipt_notrack_reg))
-               return -EINVAL;
-
-       return 0;
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_target(&ipt_notrack_reg);
-}
-
-module_init(init);
-module_exit(fini);
-MODULE_LICENSE("GPL");
index 5245bfd33d526472f543756af058b87ab214b4fd..140be51f2f01970772d3112d678962fde4c448ea 100644 (file)
@@ -33,7 +33,7 @@ MODULE_DESCRIPTION("iptables REDIRECT target module");
 /* FIXME: Take multiple ranges --RR */
 static int
 redirect_check(const char *tablename,
-              const struct ipt_entry *e,
+              const void *e,
               void *targinfo,
               unsigned int targinfosize,
               unsigned int hook_mask)
index 6693526ae128715cca526a332cf3edde758a8fdd..3eb47aae78c5b4cf1e215d9975f9c4e6c3440067 100644 (file)
@@ -282,12 +282,13 @@ static unsigned int reject(struct sk_buff **pskb,
 }
 
 static int check(const char *tablename,
-                const struct ipt_entry *e,
+                const void *e_void,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
 {
        const struct ipt_reject_info *rejinfo = targinfo;
+       const struct ipt_entry *e = e_void;
 
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
                DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
index 7a0536d864acf15125ef4eb3ff2cb2e869f140a7..a22de59bba0e0581ea29552300550a4788d1e057 100644 (file)
@@ -49,7 +49,7 @@ MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip");
 
 static int
 same_check(const char *tablename,
-             const struct ipt_entry *e,
+             const void *e,
              void *targinfo,
              unsigned int targinfosize,
              unsigned int hook_mask)
index 8db70d6908c33947917babc2c6cf2df11ce871a3..c122841e182c965d0c8629eb26987af736830001 100644 (file)
@@ -210,12 +210,13 @@ static inline int find_syn_match(const struct ipt_entry_match *m)
 /* Must specify -p tcp --syn/--tcp-flags SYN */
 static int
 ipt_tcpmss_checkentry(const char *tablename,
-                     const struct ipt_entry *e,
+                     const void *e_void,
                      void *targinfo,
                      unsigned int targinfosize,
                      unsigned int hook_mask)
 {
        const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
+       const struct ipt_entry *e = e_void;
 
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_tcpmss_info))) {
                DEBUGP("ipt_tcpmss_checkentry: targinfosize %u != %u\n",
index deadb36d442805aefba5d96465f5a478aa016fa3..3a44a56db2397352c6b012867a9bb683dd2969f9 100644 (file)
@@ -52,7 +52,7 @@ target(struct sk_buff **pskb,
 
 static int
 checkentry(const char *tablename,
-          const struct ipt_entry *e,
+          const void *e_void,
            void *targinfo,
            unsigned int targinfosize,
            unsigned int hook_mask)
index b9ae6a9382f35cd4eef6b5c175e2f0c438677647..b769eb231970ba82a4737e6cd6654254f0e1a848 100644 (file)
@@ -66,7 +66,7 @@ ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
 }
 
 static int ipt_ttl_checkentry(const char *tablename,
-               const struct ipt_entry *e,
+               const void *e,
                void *targinfo,
                unsigned int targinfosize,
                unsigned int hook_mask)
index 38641cd061234683edf4dbbeeea4e3bc05465d09..641dbc477650f6059e9577386a1664d6c9ea0206 100644 (file)
@@ -330,7 +330,7 @@ static void ipt_logfn(unsigned int pf,
 }
 
 static int ipt_ulog_checkentry(const char *tablename,
-                              const struct ipt_entry *e,
+                              const void *e,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hookmask)
index e19c2a52d00cb537e5783aeaa3e0fdd25005b744..d6b83a976518c1bd0352e40a926b7f9ac7bdbe1b 100644 (file)
@@ -29,7 +29,7 @@ static inline int match_type(u_int32_t addr, u_int16_t mask)
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
                 const struct net_device *out, const void *matchinfo,
-                int offset, int *hotdrop)
+                int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_addrtype_info *info = matchinfo;
        const struct iphdr *iph = skb->nh.iph;
@@ -43,7 +43,7 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return ret;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void *ip,
                      void *matchinfo, unsigned int matchsize,
                      unsigned int hook_mask)
 {
index a0fea847cb7282642f16b8beee14f01eb0610155..144adfec13cccff549bb4e716c979b7057e02037 100644 (file)
@@ -41,6 +41,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        struct ip_auth_hdr _ahdr, *ah;
@@ -50,7 +51,7 @@ match(const struct sk_buff *skb,
        if (offset)
                return 0;
 
-       ah = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+       ah = skb_header_pointer(skb, protoff,
                                sizeof(_ahdr), &_ahdr);
        if (ah == NULL) {
                /* We've been asked to examine this packet, and we
@@ -69,12 +70,13 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ipt_ip *ip,
+          const void *ip_void,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ipt_ah *ahinfo = matchinfo;
+       const struct ipt_ip *ip = ip_void;
 
        /* Must specify proto == AH, and no unknown invflags */
        if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
diff --git a/net/ipv4/netfilter/ipt_comment.c b/net/ipv4/netfilter/ipt_comment.c
deleted file mode 100644 (file)
index 6b76a1e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Implements a dummy match to allow attaching comments to rules
- *
- * 2003-05-13 Brad Fisher (brad@info-link.net)
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_comment.h>
-
-MODULE_AUTHOR("Brad Fisher <brad@info-link.net>");
-MODULE_DESCRIPTION("iptables comment match module");
-MODULE_LICENSE("GPL");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       /* We always match */
-       return 1;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       /* Check the size */
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_comment_info)))
-               return 0;
-       return 1;
-}
-
-static struct ipt_match comment_match = {
-       .name           = "comment",
-       .match          = match,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&comment_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&comment_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_connbytes.c b/net/ipv4/netfilter/ipt_connbytes.c
deleted file mode 100644 (file)
index d68a048..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/* Kernel module to match connection tracking byte counter.
- * GPL (C) 2002 Martin Devera (devik@cdi.cz).
- *
- * 2004-07-20 Harald Welte <laforge@netfilter.org>
- *     - reimplemented to use per-connection accounting counters
- *     - add functionality to match number of packets
- *     - add functionality to match average packet size
- *     - add support to match directions seperately
- *
- */
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_connbytes.h>
-
-#include <asm/div64.h>
-#include <asm/bitops.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
-
-/* 64bit divisor, dividend and result. dynamic precision */
-static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
-{
-       u_int32_t d = divisor;
-
-       if (divisor > 0xffffffffULL) {
-               unsigned int shift = fls(divisor >> 32);
-
-               d = divisor >> shift;
-               dividend >>= shift;
-       }
-
-       do_div(dividend, d);
-       return dividend;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_connbytes_info *sinfo = matchinfo;
-       u_int64_t what = 0;     /* initialize to make gcc happy */
-       const struct ip_conntrack_counter *counters;
-
-       if (!(counters = nf_ct_get_counters(skb)))
-               return 0; /* no match */
-
-       switch (sinfo->what) {
-       case IPT_CONNBYTES_PKTS:
-               switch (sinfo->direction) {
-               case IPT_CONNBYTES_DIR_ORIGINAL:
-                       what = counters[IP_CT_DIR_ORIGINAL].packets;
-                       break;
-               case IPT_CONNBYTES_DIR_REPLY:
-                       what = counters[IP_CT_DIR_REPLY].packets;
-                       break;
-               case IPT_CONNBYTES_DIR_BOTH:
-                       what = counters[IP_CT_DIR_ORIGINAL].packets;
-                       what += counters[IP_CT_DIR_REPLY].packets;
-                       break;
-               }
-               break;
-       case IPT_CONNBYTES_BYTES:
-               switch (sinfo->direction) {
-               case IPT_CONNBYTES_DIR_ORIGINAL:
-                       what = counters[IP_CT_DIR_ORIGINAL].bytes;
-                       break;
-               case IPT_CONNBYTES_DIR_REPLY:
-                       what = counters[IP_CT_DIR_REPLY].bytes;
-                       break;
-               case IPT_CONNBYTES_DIR_BOTH:
-                       what = counters[IP_CT_DIR_ORIGINAL].bytes;
-                       what += counters[IP_CT_DIR_REPLY].bytes;
-                       break;
-               }
-               break;
-       case IPT_CONNBYTES_AVGPKT:
-               switch (sinfo->direction) {
-               case IPT_CONNBYTES_DIR_ORIGINAL:
-                       what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
-                                       counters[IP_CT_DIR_ORIGINAL].packets);
-                       break;
-               case IPT_CONNBYTES_DIR_REPLY:
-                       what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
-                                       counters[IP_CT_DIR_REPLY].packets);
-                       break;
-               case IPT_CONNBYTES_DIR_BOTH:
-                       {
-                               u_int64_t bytes;
-                               u_int64_t pkts;
-                               bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
-                                       counters[IP_CT_DIR_REPLY].bytes;
-                               pkts = counters[IP_CT_DIR_ORIGINAL].packets+
-                                       counters[IP_CT_DIR_REPLY].packets;
-
-                               /* FIXME_THEORETICAL: what to do if sum
-                                * overflows ? */
-
-                               what = div64_64(bytes, pkts);
-                       }
-                       break;
-               }
-               break;
-       }
-
-       if (sinfo->count.to)
-               return (what <= sinfo->count.to && what >= sinfo->count.from);
-       else
-               return (what >= sinfo->count.from);
-}
-
-static int check(const char *tablename,
-                const struct ipt_ip *ip,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       const struct ipt_connbytes_info *sinfo = matchinfo;
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
-               return 0;
-
-       if (sinfo->what != IPT_CONNBYTES_PKTS &&
-           sinfo->what != IPT_CONNBYTES_BYTES &&
-           sinfo->what != IPT_CONNBYTES_AVGPKT)
-               return 0;
-
-       if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
-           sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
-           sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match state_match = {
-       .name           = "connbytes",
-       .match          = &match,
-       .checkentry     = &check,
-       .me             = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&state_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&state_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_connmark.c b/net/ipv4/netfilter/ipt_connmark.c
deleted file mode 100644 (file)
index 5306ef2..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* This kernel module matches connection mark values set by the
- * CONNMARK target
- *
- * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
- * by Henrik Nordstrom <hno@marasystems.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/skbuff.h>
-
-MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
-MODULE_DESCRIPTION("IP tables connmark match module");
-MODULE_LICENSE("GPL");
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_connmark.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_connmark_info *info = matchinfo;
-       u_int32_t ctinfo;
-       const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
-       if (!ctmark)
-               return 0;
-
-       return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ipt_ip *ip,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-{
-       struct ipt_connmark_info *cm = 
-                               (struct ipt_connmark_info *)matchinfo;
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
-               return 0;
-
-       if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
-               printk(KERN_WARNING "connmark: only support 32bit mark\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_match connmark_match = {
-       .name = "connmark",
-       .match = &match,
-       .checkentry = &checkentry,
-       .me = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&connmark_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&connmark_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_conntrack.c b/net/ipv4/netfilter/ipt_conntrack.c
deleted file mode 100644 (file)
index c8d1870..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/* Kernel module to match connection tracking information.
- * Superset of Rusty's minimalistic state match.
- *
- * (C) 2001  Marc Boucher (marc@mbsi.ca).
- *
- * 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/skbuff.h>
-
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
-#else
-#include <net/netfilter/nf_conntrack.h>
-#endif
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_conntrack.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables connection tracking match module");
-
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_conntrack_info *sinfo = matchinfo;
-       struct ip_conntrack *ct;
-       enum ip_conntrack_info ctinfo;
-       unsigned int statebit;
-
-       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
-
-#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
-
-       if (ct == &ip_conntrack_untracked)
-               statebit = IPT_CONNTRACK_STATE_UNTRACKED;
-       else if (ct)
-               statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
-       else
-               statebit = IPT_CONNTRACK_STATE_INVALID;
-       if(sinfo->flags & IPT_CONNTRACK_STATE) {
-               if (ct) {
-                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
-                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
-                               statebit |= IPT_CONNTRACK_STATE_SNAT;
-
-                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
-                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
-                               statebit |= IPT_CONNTRACK_STATE_DNAT;
-               }
-
-               if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_PROTO) {
-               if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_STATUS) {
-               if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
-               unsigned long expires;
-
-               if(!ct)
-                       return 0;
-
-               expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
-
-               if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
-                       return 0;
-       }
-
-       return 1;
-}
-
-#else /* CONFIG_IP_NF_CONNTRACK */
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_conntrack_info *sinfo = matchinfo;
-       struct nf_conn *ct;
-       enum ip_conntrack_info ctinfo;
-       unsigned int statebit;
-
-       ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
-
-#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
-
-       if (ct == &nf_conntrack_untracked)
-               statebit = IPT_CONNTRACK_STATE_UNTRACKED;
-       else if (ct)
-               statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
-       else
-               statebit = IPT_CONNTRACK_STATE_INVALID;
-       if(sinfo->flags & IPT_CONNTRACK_STATE) {
-               if (ct) {
-                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
-                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
-                               statebit |= IPT_CONNTRACK_STATE_SNAT;
-
-                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
-                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
-                               statebit |= IPT_CONNTRACK_STATE_DNAT;
-               }
-
-               if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_PROTO) {
-               if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
-               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_STATUS) {
-               if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
-                       return 0;
-       }
-
-       if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
-               unsigned long expires;
-
-               if(!ct)
-                       return 0;
-
-               expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
-
-               if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
-                       return 0;
-       }
-
-       return 1;
-}
-
-#endif /* CONFIG_NF_IP_CONNTRACK */
-
-static int check(const char *tablename,
-                const struct ipt_ip *ip,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match conntrack_match = {
-       .name           = "conntrack",
-       .match          = &match,
-       .checkentry     = &check,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       need_ip_conntrack();
-       return ipt_register_match(&conntrack_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&conntrack_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_dccp.c b/net/ipv4/netfilter/ipt_dccp.c
deleted file mode 100644 (file)
index ad3278b..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * iptables module for DCCP protocol header matching
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
-#include <linux/spinlock.h>
-#include <net/ip.h>
-#include <linux/dccp.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_dccp.h>
-
-#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
-                                 || (!!((invflag) & (option)) ^ (cond)))
-
-static unsigned char *dccp_optbuf;
-static DEFINE_SPINLOCK(dccp_buflock);
-
-static inline int
-dccp_find_option(u_int8_t option,
-                const struct sk_buff *skb,
-                const struct dccp_hdr *dh,
-                int *hotdrop)
-{
-       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-       unsigned char *op;
-       unsigned int optoff = __dccp_hdr_len(dh);
-       unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
-       unsigned int i;
-
-       if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
-               *hotdrop = 1;
-               return 0;
-       }
-
-       if (!optlen)
-               return 0;
-
-       spin_lock_bh(&dccp_buflock);
-       op = skb_header_pointer(skb,
-                               skb->nh.iph->ihl*4 + optoff,
-                               optlen, dccp_optbuf);
-       if (op == NULL) {
-               /* If we don't have the whole header, drop packet. */
-               spin_unlock_bh(&dccp_buflock);
-               *hotdrop = 1;
-               return 0;
-       }
-
-       for (i = 0; i < optlen; ) {
-               if (op[i] == option) {
-                       spin_unlock_bh(&dccp_buflock);
-                       return 1;
-               }
-
-               if (op[i] < 2) 
-                       i++;
-               else 
-                       i += op[i+1]?:1;
-       }
-
-       spin_unlock_bh(&dccp_buflock);
-       return 0;
-}
-
-
-static inline int
-match_types(const struct dccp_hdr *dh, u_int16_t typemask)
-{
-       return (typemask & (1 << dh->dccph_type));
-}
-
-static inline int
-match_option(u_int8_t option, const struct sk_buff *skb,
-            const struct dccp_hdr *dh, int *hotdrop)
-{
-       return dccp_find_option(option, skb, dh, hotdrop);
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_dccp_info *info = 
-                               (const struct ipt_dccp_info *)matchinfo;
-       struct dccp_hdr _dh, *dh;
-
-       if (offset)
-               return 0;
-       
-       dh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_dh), &_dh);
-       if (dh == NULL) {
-               *hotdrop = 1;
-               return 0;
-               }
-
-       return  DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) 
-                       && (ntohs(dh->dccph_sport) <= info->spts[1])), 
-                       IPT_DCCP_SRC_PORTS, info->flags, info->invflags)
-               && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) 
-                       && (ntohs(dh->dccph_dport) <= info->dpts[1])), 
-                       IPT_DCCP_DEST_PORTS, info->flags, info->invflags)
-               && DCCHECK(match_types(dh, info->typemask),
-                          IPT_DCCP_TYPE, info->flags, info->invflags)
-               && DCCHECK(match_option(info->option, skb, dh, hotdrop),
-                          IPT_DCCP_OPTION, info->flags, info->invflags);
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ipt_ip *ip,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-{
-       const struct ipt_dccp_info *info;
-
-       info = (const struct ipt_dccp_info *)matchinfo;
-
-       return ip->proto == IPPROTO_DCCP
-               && !(ip->invflags & IPT_INV_PROTO)
-               && matchsize == IPT_ALIGN(sizeof(struct ipt_dccp_info))
-               && !(info->flags & ~IPT_DCCP_VALID_FLAGS)
-               && !(info->invflags & ~IPT_DCCP_VALID_FLAGS)
-               && !(info->invflags & ~info->flags);
-}
-
-static struct ipt_match dccp_match = 
-{ 
-       .name           = "dccp",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       int ret;
-
-       /* doff is 8 bits, so the maximum option size is (4*256).  Don't put
-        * this in BSS since DaveM is worried about locked TLB's for kernel
-        * BSS. */
-       dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
-       if (!dccp_optbuf)
-               return -ENOMEM;
-       ret = ipt_register_match(&dccp_match);
-       if (ret)
-               kfree(dccp_optbuf);
-
-       return ret;
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&dccp_match);
-       kfree(dccp_optbuf);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("Match for DCCP protocol packets");
-
index 5df52a64a5d4016b43c6952d2a30177a69235e63..92063b4f8602c8de8c34b2dcf33426fcf7ce7353 100644 (file)
@@ -21,7 +21,7 @@ MODULE_LICENSE("GPL");
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
                 const struct net_device *out, const void *matchinfo,
-                int offset, int *hotdrop)
+                int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_dscp_info *info = matchinfo;
        const struct iphdr *iph = skb->nh.iph;
@@ -31,7 +31,7 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ info->invert;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void *ip,
                      void *matchinfo, unsigned int matchsize,
                      unsigned int hook_mask)
 {
index b6f7181e89ccf0e48806a15aacc40fb711f06e81..e68b0c7981f0c7d4594d3e42854914873a43562a 100644 (file)
@@ -67,7 +67,7 @@ static inline int match_tcp(const struct sk_buff *skb,
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
                 const struct net_device *out, const void *matchinfo,
-                int offset, int *hotdrop)
+                int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_ecn_info *info = matchinfo;
 
@@ -85,11 +85,12 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return 1;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void *ip_void,
                      void *matchinfo, unsigned int matchsize,
                      unsigned int hook_mask)
 {
        const struct ipt_ecn_info *info = matchinfo;
+       const struct ipt_ip *ip = ip_void;
 
        if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
                return 0;
index e1d0dd31e11740a9ed4578bfdfc11471dadbb860..9de191a8162da78e3177a5e0b356d128a39363b2 100644 (file)
@@ -42,6 +42,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        struct ip_esp_hdr _esp, *eh;
@@ -51,7 +52,7 @@ match(const struct sk_buff *skb,
        if (offset)
                return 0;
 
-       eh = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+       eh = skb_header_pointer(skb, protoff,
                                sizeof(_esp), &_esp);
        if (eh == NULL) {
                /* We've been asked to examine this packet, and we
@@ -70,12 +71,13 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ipt_ip *ip,
+          const void *ip_void,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
 {
        const struct ipt_esp *espinfo = matchinfo;
+       const struct ipt_ip *ip = ip_void;
 
        /* Must specify proto == ESP, and no unknown invflags */
        if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
index 2dd1cccbdab9e938f20920c9355ab1a834bdc0ff..4fe48c1bd5f3f2b08ac6e600eb43f13d6e5dc4fb 100644 (file)
@@ -429,6 +429,7 @@ hashlimit_match(const struct sk_buff *skb,
                const struct net_device *out,
                const void *matchinfo,
                int offset,
+               unsigned int protoff,
                int *hotdrop)
 {
        struct ipt_hashlimit_info *r = 
@@ -504,7 +505,7 @@ hashlimit_match(const struct sk_buff *skb,
 
 static int
 hashlimit_checkentry(const char *tablename,
-                    const struct ipt_ip *ip,
+                    const void *inf,
                     void *matchinfo,
                     unsigned int matchsize,
                     unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c
deleted file mode 100644 (file)
index aef649e..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/* iptables module to match on related connections */
-/*
- * (C) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
- *
- * 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.
- *
- *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
- *              - Port to newnat infrastructure
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter.h>
-#include <linux/interrupt.h>
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-#include <linux/netfilter_ipv4/ip_conntrack.h>
-#include <linux/netfilter_ipv4/ip_conntrack_core.h>
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
-#else
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_core.h>
-#include <net/netfilter/nf_conntrack_helper.h>
-#endif
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_helper.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
-MODULE_DESCRIPTION("iptables helper match module");
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_helper_info *info = matchinfo;
-       struct ip_conntrack *ct;
-       enum ip_conntrack_info ctinfo;
-       int ret = info->invert;
-       
-       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
-       if (!ct) {
-               DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
-               return ret;
-       }
-
-       if (!ct->master) {
-               DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
-               return ret;
-       }
-
-       read_lock_bh(&ip_conntrack_lock);
-       if (!ct->master->helper) {
-               DEBUGP("ipt_helper: master ct %p has no helper\n", 
-                       exp->expectant);
-               goto out_unlock;
-       }
-
-       DEBUGP("master's name = %s , info->name = %s\n", 
-               ct->master->helper->name, info->name);
-
-       if (info->name[0] == '\0')
-               ret ^= 1;
-       else
-               ret ^= !strncmp(ct->master->helper->name, info->name, 
-                               strlen(ct->master->helper->name));
-out_unlock:
-       read_unlock_bh(&ip_conntrack_lock);
-       return ret;
-}
-
-#else /* CONFIG_IP_NF_CONNTRACK */
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_helper_info *info = matchinfo;
-       struct nf_conn *ct;
-       enum ip_conntrack_info ctinfo;
-       int ret = info->invert;
-       
-       ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
-       if (!ct) {
-               DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
-               return ret;
-       }
-
-       if (!ct->master) {
-               DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
-               return ret;
-       }
-
-       read_lock_bh(&nf_conntrack_lock);
-       if (!ct->master->helper) {
-               DEBUGP("ipt_helper: master ct %p has no helper\n", 
-                       exp->expectant);
-               goto out_unlock;
-       }
-
-       DEBUGP("master's name = %s , info->name = %s\n", 
-               ct->master->helper->name, info->name);
-
-       if (info->name[0] == '\0')
-               ret ^= 1;
-       else
-               ret ^= !strncmp(ct->master->helper->name, info->name, 
-                               strlen(ct->master->helper->name));
-out_unlock:
-       read_unlock_bh(&nf_conntrack_lock);
-       return ret;
-}
-#endif
-
-static int check(const char *tablename,
-                const struct ipt_ip *ip,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       struct ipt_helper_info *info = matchinfo;
-
-       info->name[29] = '\0';
-
-       /* verify size */
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match helper_match = {
-       .name           = "helper",
-       .match          = &match,
-       .checkentry     = &check,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       need_ip_conntrack();
-       return ipt_register_match(&helper_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&helper_match);
-}
-
-module_init(init);
-module_exit(fini);
-
index b835b7b2e56044b2991875418205a95d44a39a73..13fb16fb78923d2bcdbde8bca839e396a8682256 100644 (file)
@@ -28,7 +28,7 @@ match(const struct sk_buff *skb,
       const struct net_device *in,
       const struct net_device *out,
       const void *matchinfo,
-      int offset, int *hotdrop)
+      int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_iprange_info *info = matchinfo;
        const struct iphdr *iph = skb->nh.iph;
@@ -63,7 +63,7 @@ match(const struct sk_buff *skb,
 }
 
 static int check(const char *tablename,
-                const struct ipt_ip *ip,
+                const void *inf,
                 void *matchinfo,
                 unsigned int matchsize,
                 unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_length.c b/net/ipv4/netfilter/ipt_length.c
deleted file mode 100644 (file)
index 4eabcfb..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Kernel module to match packet length. */
-/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
- *
- * 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/skbuff.h>
-
-#include <linux/netfilter_ipv4/ipt_length.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
-MODULE_DESCRIPTION("IP tables packet length matching module");
-MODULE_LICENSE("GPL");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_length_info *info = matchinfo;
-       u_int16_t pktlen = ntohs(skb->nh.iph->tot_len);
-       
-       return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_length_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match length_match = {
-       .name           = "length",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&length_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&length_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_limit.c b/net/ipv4/netfilter/ipt_limit.c
deleted file mode 100644 (file)
index 0c24dcc..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Kernel module to control the rate
- *
- * 2 September 1999: Changed from the target RATE to the match
- *                   `limit', removed logging.  Did I mention that
- *                   Alexey is a fucking genius?
- *                   Rusty Russell (rusty@rustcorp.com.au).  */
-
-/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
- * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
- *
- * 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/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_limit.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
-MODULE_DESCRIPTION("iptables rate limit match");
-
-/* The algorithm used is the Simple Token Bucket Filter (TBF)
- * see net/sched/sch_tbf.c in the linux source tree
- */
-
-static DEFINE_SPINLOCK(limit_lock);
-
-/* Rusty: This is my (non-mathematically-inclined) understanding of
-   this algorithm.  The `average rate' in jiffies becomes your initial
-   amount of credit `credit' and the most credit you can ever have
-   `credit_cap'.  The `peak rate' becomes the cost of passing the
-   test, `cost'.
-
-   `prev' tracks the last packet hit: you gain one credit per jiffy.
-   If you get credit balance more than this, the extra credit is
-   discarded.  Every time the match passes, you lose `cost' credits;
-   if you don't have that many, the test fails.
-
-   See Alexey's formal explanation in net/sched/sch_tbf.c.
-
-   To get the maxmum range, we multiply by this factor (ie. you get N
-   credits per jiffy).  We want to allow a rate as low as 1 per day
-   (slowest userspace tool allows), which means
-   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */
-#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
-
-/* Repeated shift and or gives us all 1s, final shift and add 1 gives
- * us the power of 2 below the theoretical max, so GCC simply does a
- * shift. */
-#define _POW2_BELOW2(x) ((x)|((x)>>1))
-#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
-#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
-#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
-#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
-#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
-
-#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
-
-static int
-ipt_limit_match(const struct sk_buff *skb,
-               const struct net_device *in,
-               const struct net_device *out,
-               const void *matchinfo,
-               int offset,
-               int *hotdrop)
-{
-       struct ipt_rateinfo *r = ((struct ipt_rateinfo *)matchinfo)->master;
-       unsigned long now = jiffies;
-
-       spin_lock_bh(&limit_lock);
-       r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
-       if (r->credit > r->credit_cap)
-               r->credit = r->credit_cap;
-
-       if (r->credit >= r->cost) {
-               /* We're not limited. */
-               r->credit -= r->cost;
-               spin_unlock_bh(&limit_lock);
-               return 1;
-       }
-
-               spin_unlock_bh(&limit_lock);
-       return 0;
-}
-
-/* Precision saver. */
-static u_int32_t
-user2credits(u_int32_t user)
-{
-       /* If multiplying would overflow... */
-       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
-               /* Divide first. */
-               return (user / IPT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
-
-       return (user * HZ * CREDITS_PER_JIFFY) / IPT_LIMIT_SCALE;
-}
-
-static int
-ipt_limit_checkentry(const char *tablename,
-                    const struct ipt_ip *ip,
-                    void *matchinfo,
-                    unsigned int matchsize,
-                    unsigned int hook_mask)
-{
-       struct ipt_rateinfo *r = matchinfo;
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_rateinfo)))
-               return 0;
-
-       /* Check for overflow. */
-       if (r->burst == 0
-           || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-               printk("Overflow in ipt_limit, try lower: %u/%u\n",
-                      r->avg, r->burst);
-               return 0;
-       }
-
-       /* User avg in seconds * IPT_LIMIT_SCALE: convert to jiffies *
-          128. */
-       r->prev = jiffies;
-       r->credit = user2credits(r->avg * r->burst);     /* Credits full. */
-       r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
-       r->cost = user2credits(r->avg);
-
-       /* For SMP, we only want to use one set of counters. */
-       r->master = r;
-
-       return 1;
-}
-
-static struct ipt_match ipt_limit_reg = {
-       .name           = "limit",
-       .match          = ipt_limit_match,
-       .checkentry     = ipt_limit_checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       if (ipt_register_match(&ipt_limit_reg))
-               return -EINVAL;
-       return 0;
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&ipt_limit_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_mac.c b/net/ipv4/netfilter/ipt_mac.c
deleted file mode 100644 (file)
index 1b9bb45..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Kernel module to match MAC address parameters. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.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/skbuff.h>
-#include <linux/if_ether.h>
-#include <linux/etherdevice.h>
-
-#include <linux/netfilter_ipv4/ipt_mac.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("iptables mac matching module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-    const struct ipt_mac_info *info = matchinfo;
-
-    /* Is mac pointer valid? */
-    return (skb->mac.raw >= skb->head
-           && (skb->mac.raw + ETH_HLEN) <= skb->data
-           /* If so, compare... */
-           && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
-               ^ info->invert));
-}
-
-static int
-ipt_mac_checkentry(const char *tablename,
-                  const struct ipt_ip *ip,
-                  void *matchinfo,
-                  unsigned int matchsize,
-                  unsigned int hook_mask)
-{
-       /* FORWARD isn't always valid, but it's nice to be able to do --RR */
-       if (hook_mask
-           & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
-               | (1 << NF_IP_FORWARD))) {
-               printk("ipt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-               return 0;
-       }
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_mac_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match mac_match = {
-       .name           = "mac",
-       .match          = &match,
-       .checkentry     = &ipt_mac_checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&mac_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&mac_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_mark.c b/net/ipv4/netfilter/ipt_mark.c
deleted file mode 100644 (file)
index 00bef6c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Kernel module to match NFMARK values. */
-
-/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *
- * 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/skbuff.h>
-
-#include <linux/netfilter_ipv4/ipt_mark.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables mark matching module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_mark_info *info = matchinfo;
-
-       return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       struct ipt_mark_info *minfo = (struct ipt_mark_info *) matchinfo;
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_mark_info)))
-               return 0;
-
-       if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
-               printk(KERN_WARNING "mark: only supports 32bit mark\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_match mark_match = {
-       .name           = "mark",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&mark_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&mark_match);
-}
-
-module_init(init);
-module_exit(fini);
index 99e8188162e25b3aaf00ef3e01e9aadc6d4a2cee..2d52326553f1fa1b36cea95ada0685bdd8115e51 100644 (file)
@@ -97,6 +97,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        u16 _ports[2], *pptr;
@@ -105,7 +106,7 @@ match(const struct sk_buff *skb,
        if (offset)
                return 0;
 
-       pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+       pptr = skb_header_pointer(skb, protoff,
                                  sizeof(_ports), _ports);
        if (pptr == NULL) {
                /* We've been asked to examine this packet, and we
@@ -128,6 +129,7 @@ match_v1(const struct sk_buff *skb,
         const struct net_device *out,
         const void *matchinfo,
         int offset,
+        unsigned int protoff,
         int *hotdrop)
 {
        u16 _ports[2], *pptr;
@@ -136,7 +138,7 @@ match_v1(const struct sk_buff *skb,
        if (offset)
                return 0;
 
-       pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
+       pptr = skb_header_pointer(skb, protoff,
                                  sizeof(_ports), _ports);
        if (pptr == NULL) {
                /* We've been asked to examine this packet, and we
@@ -154,7 +156,7 @@ match_v1(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ipt_ip *ip,
+          const void *ip,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
@@ -164,7 +166,7 @@ checkentry(const char *tablename,
 
 static int
 checkentry_v1(const char *tablename,
-             const struct ipt_ip *ip,
+             const void *ip,
              void *matchinfo,
              unsigned int matchsize,
              unsigned int hook_mask)
index 0cee2862ed85f46d3fbbbe96c908c16aeb92489d..4843d0c9734f28c26a3d0bf35f4acb86f4204442 100644 (file)
@@ -27,6 +27,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        const struct ipt_owner_info *info = matchinfo;
@@ -51,7 +52,7 @@ match(const struct sk_buff *skb,
 
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_physdev.c b/net/ipv4/netfilter/ipt_physdev.c
deleted file mode 100644 (file)
index 03f5548..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Kernel module to match the bridge port in and
- * out device for IP packets coming into contact with a bridge. */
-
-/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
- *
- * 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/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ipt_physdev.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_bridge.h>
-#define MATCH   1
-#define NOMATCH 0
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
-MODULE_DESCRIPTION("iptables bridge physical device match module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       int i;
-       static const char nulldevname[IFNAMSIZ];
-       const struct ipt_physdev_info *info = matchinfo;
-       unsigned int ret;
-       const char *indev, *outdev;
-       struct nf_bridge_info *nf_bridge;
-
-       /* Not a bridged IP packet or no info available yet:
-        * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
-        * the destination device will be a bridge. */
-       if (!(nf_bridge = skb->nf_bridge)) {
-               /* Return MATCH if the invert flags of the used options are on */
-               if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) &&
-                   !(info->invert & IPT_PHYSDEV_OP_BRIDGED))
-                       return NOMATCH;
-               if ((info->bitmask & IPT_PHYSDEV_OP_ISIN) &&
-                   !(info->invert & IPT_PHYSDEV_OP_ISIN))
-                       return NOMATCH;
-               if ((info->bitmask & IPT_PHYSDEV_OP_ISOUT) &&
-                   !(info->invert & IPT_PHYSDEV_OP_ISOUT))
-                       return NOMATCH;
-               if ((info->bitmask & IPT_PHYSDEV_OP_IN) &&
-                   !(info->invert & IPT_PHYSDEV_OP_IN))
-                       return NOMATCH;
-               if ((info->bitmask & IPT_PHYSDEV_OP_OUT) &&
-                   !(info->invert & IPT_PHYSDEV_OP_OUT))
-                       return NOMATCH;
-               return MATCH;
-       }
-
-       /* This only makes sense in the FORWARD and POSTROUTING chains */
-       if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) &&
-           (!!(nf_bridge->mask & BRNF_BRIDGED) ^
-           !(info->invert & IPT_PHYSDEV_OP_BRIDGED)))
-               return NOMATCH;
-
-       if ((info->bitmask & IPT_PHYSDEV_OP_ISIN &&
-           (!nf_bridge->physindev ^ !!(info->invert & IPT_PHYSDEV_OP_ISIN))) ||
-           (info->bitmask & IPT_PHYSDEV_OP_ISOUT &&
-           (!nf_bridge->physoutdev ^ !!(info->invert & IPT_PHYSDEV_OP_ISOUT))))
-               return NOMATCH;
-
-       if (!(info->bitmask & IPT_PHYSDEV_OP_IN))
-               goto match_outdev;
-       indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
-       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-               ret |= (((const unsigned int *)indev)[i]
-                       ^ ((const unsigned int *)info->physindev)[i])
-                       & ((const unsigned int *)info->in_mask)[i];
-       }
-
-       if ((ret == 0) ^ !(info->invert & IPT_PHYSDEV_OP_IN))
-               return NOMATCH;
-
-match_outdev:
-       if (!(info->bitmask & IPT_PHYSDEV_OP_OUT))
-               return MATCH;
-       outdev = nf_bridge->physoutdev ?
-                nf_bridge->physoutdev->name : nulldevname;
-       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-               ret |= (((const unsigned int *)outdev)[i]
-                       ^ ((const unsigned int *)info->physoutdev)[i])
-                       & ((const unsigned int *)info->out_mask)[i];
-       }
-
-       return (ret != 0) ^ !(info->invert & IPT_PHYSDEV_OP_OUT);
-}
-
-static int
-checkentry(const char *tablename,
-                      const struct ipt_ip *ip,
-                      void *matchinfo,
-                      unsigned int matchsize,
-                      unsigned int hook_mask)
-{
-       const struct ipt_physdev_info *info = matchinfo;
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_physdev_info)))
-               return 0;
-       if (!(info->bitmask & IPT_PHYSDEV_OP_MASK) ||
-           info->bitmask & ~IPT_PHYSDEV_OP_MASK)
-               return 0;
-       return 1;
-}
-
-static struct ipt_match physdev_match = {
-       .name           = "physdev",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&physdev_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&physdev_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_pkttype.c b/net/ipv4/netfilter/ipt_pkttype.c
deleted file mode 100644 (file)
index 8ddb1dc..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* (C) 1999-2001 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-
-#include <linux/netfilter_ipv4/ipt_pkttype.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michal Ludvig <michal@logix.cz>");
-MODULE_DESCRIPTION("IP tables match to match on linklayer packet type");
-
-static int match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-    const struct ipt_pkttype_info *info = matchinfo;
-
-    return (skb->pkt_type == info->pkttype) ^ info->invert;
-}
-
-static int checkentry(const char *tablename,
-                  const struct ipt_ip *ip,
-                  void *matchinfo,
-                  unsigned int matchsize,
-                  unsigned int hook_mask)
-{
-/*
-       if (hook_mask
-           & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
-               | (1 << NF_IP_FORWARD))) {
-               printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
-               return 0;
-       }
-*/
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match pkttype_match = {
-       .name           = "pkttype",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&pkttype_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&pkttype_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_realm.c b/net/ipv4/netfilter/ipt_realm.c
deleted file mode 100644 (file)
index 54a6897..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* IP tables module for matching the routing realm
- *
- * $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $
- *
- * (C) 2003 by Sampsa Ranta <sampsa@netsonic.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
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <net/route.h>
-
-#include <linux/netfilter_ipv4/ipt_realm.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("iptables realm match");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_realm_info *info = matchinfo;
-       struct dst_entry *dst = skb->dst;
-    
-       return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
-}
-
-static int check(const char *tablename,
-                 const struct ipt_ip *ip,
-                 void *matchinfo,
-                 unsigned int matchsize,
-                 unsigned int hook_mask)
-{
-       if (hook_mask
-           & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
-               (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) {
-               printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
-                      "LOCAL_IN or FORWARD.\n");
-               return 0;
-       }
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info))) {
-               printk("ipt_realm: invalid matchsize.\n");
-               return 0;
-       }
-       return 1;
-}
-
-static struct ipt_match realm_match = {
-       .name           = "realm",
-       .match          = match, 
-       .checkentry     = check,
-       .me             = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&realm_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&realm_match);
-}
-
-module_init(init);
-module_exit(fini);
index 5ddccb18c65e41f0326af34494dd2f76be6a02cd..44611d6d14f5c4d95e906773b2006d7ff6e40294 100644 (file)
@@ -104,6 +104,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop);
 
 /* Function to hash a given address into the hash table of table_size size */
@@ -317,7 +318,7 @@ static int ip_recent_ctrl(struct file *file, const char __user *input, unsigned
        skb->nh.iph->daddr = 0;
        /* Clear ttl since we have no way of knowing it */
        skb->nh.iph->ttl = 0;
-       match(skb,NULL,NULL,info,0,NULL);
+       match(skb,NULL,NULL,info,0,0,NULL);
 
        kfree(skb->nh.iph);
 out_free_skb:
@@ -357,6 +358,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        int pkt_count, hits_found, ans;
@@ -654,7 +656,7 @@ match(const struct sk_buff *skb,
  */
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv4/netfilter/ipt_sctp.c b/net/ipv4/netfilter/ipt_sctp.c
deleted file mode 100644 (file)
index fe2b327..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <net/ip.h>
-#include <linux/sctp.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_sctp.h>
-
-#ifdef DEBUG_SCTP
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
-#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
-                                             || (!!((invflag) & (option)) ^ (cond)))
-
-static int
-match_flags(const struct ipt_sctp_flag_info *flag_info,
-           const int flag_count,
-           u_int8_t chunktype,
-           u_int8_t chunkflags)
-{
-       int i;
-
-       for (i = 0; i < flag_count; i++) {
-               if (flag_info[i].chunktype == chunktype) {
-                       return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
-               }
-       }
-
-       return 1;
-}
-
-static int
-match_packet(const struct sk_buff *skb,
-            const u_int32_t *chunkmap,
-            int chunk_match_type,
-            const struct ipt_sctp_flag_info *flag_info,
-            const int flag_count,
-            int *hotdrop)
-{
-       int offset;
-       u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
-       sctp_chunkhdr_t _sch, *sch;
-
-#ifdef DEBUG_SCTP
-       int i = 0;
-#endif
-
-       if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
-               SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
-       }
-
-       offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
-       do {
-               sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
-               if (sch == NULL) {
-                       duprintf("Dropping invalid SCTP packet.\n");
-                       *hotdrop = 1;
-                       return 0;
-               }
-
-               duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
-                               ++i, offset, sch->type, htons(sch->length), sch->flags);
-
-               offset += (htons(sch->length) + 3) & ~3;
-
-               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
-
-               if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) {
-                       switch (chunk_match_type) {
-                       case SCTP_CHUNK_MATCH_ANY:
-                               if (match_flags(flag_info, flag_count, 
-                                       sch->type, sch->flags)) {
-                                       return 1;
-                               }
-                               break;
-
-                       case SCTP_CHUNK_MATCH_ALL:
-                               if (match_flags(flag_info, flag_count, 
-                                       sch->type, sch->flags)) {
-                                       SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
-                               }
-                               break;
-
-                       case SCTP_CHUNK_MATCH_ONLY:
-                               if (!match_flags(flag_info, flag_count, 
-                                       sch->type, sch->flags)) {
-                                       return 0;
-                               }
-                               break;
-                       }
-               } else {
-                       switch (chunk_match_type) {
-                       case SCTP_CHUNK_MATCH_ONLY:
-                               return 0;
-                       }
-               }
-       } while (offset < skb->len);
-
-       switch (chunk_match_type) {
-       case SCTP_CHUNK_MATCH_ALL:
-               return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
-       case SCTP_CHUNK_MATCH_ANY:
-               return 0;
-       case SCTP_CHUNK_MATCH_ONLY:
-               return 1;
-       }
-
-       /* This will never be reached, but required to stop compiler whine */
-       return 0;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_sctp_info *info;
-       sctp_sctphdr_t _sh, *sh;
-
-       info = (const struct ipt_sctp_info *)matchinfo;
-
-       if (offset) {
-               duprintf("Dropping non-first fragment.. FIXME\n");
-               return 0;
-       }
-       
-       sh = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_sh), &_sh);
-       if (sh == NULL) {
-               duprintf("Dropping evil TCP offset=0 tinygram.\n");
-               *hotdrop = 1;
-               return 0;
-               }
-       duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
-
-       return  SCCHECK(((ntohs(sh->source) >= info->spts[0]) 
-                       && (ntohs(sh->source) <= info->spts[1])), 
-                       IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
-               && SCCHECK(((ntohs(sh->dest) >= info->dpts[0]) 
-                       && (ntohs(sh->dest) <= info->dpts[1])), 
-                       IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
-               && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
-                                       info->flag_info, info->flag_count, 
-                                       hotdrop),
-                          IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ipt_ip *ip,
-          void *matchinfo,
-          unsigned int matchsize,
-          unsigned int hook_mask)
-{
-       const struct ipt_sctp_info *info;
-
-       info = (const struct ipt_sctp_info *)matchinfo;
-
-       return ip->proto == IPPROTO_SCTP
-               && !(ip->invflags & IPT_INV_PROTO)
-               && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
-               && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
-               && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
-               && !(info->invflags & ~info->flags)
-               && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
-                       (info->chunk_match_type &
-                               (SCTP_CHUNK_MATCH_ALL 
-                               | SCTP_CHUNK_MATCH_ANY
-                               | SCTP_CHUNK_MATCH_ONLY)));
-}
-
-static struct ipt_match sctp_match = 
-{ 
-       .list = { NULL, NULL},
-       .name = "sctp",
-       .match = &match,
-       .checkentry = &checkentry,
-       .destroy = NULL,
-       .me = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&sctp_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&sctp_match);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Kiran Kumar Immidi");
-MODULE_DESCRIPTION("Match for SCTP protocol packets");
-
diff --git a/net/ipv4/netfilter/ipt_state.c b/net/ipv4/netfilter/ipt_state.c
deleted file mode 100644 (file)
index 4d7f16b..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Kernel module to match connection tracking information. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.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/skbuff.h>
-#include <net/netfilter/nf_conntrack_compat.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_state.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
-MODULE_DESCRIPTION("iptables connection tracking state match module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_state_info *sinfo = matchinfo;
-       enum ip_conntrack_info ctinfo;
-       unsigned int statebit;
-
-       if (nf_ct_is_untracked(skb))
-               statebit = IPT_STATE_UNTRACKED;
-       else if (!nf_ct_get_ctinfo(skb, &ctinfo))
-               statebit = IPT_STATE_INVALID;
-       else
-               statebit = IPT_STATE_BIT(ctinfo);
-
-       return (sinfo->statemask & statebit);
-}
-
-static int check(const char *tablename,
-                const struct ipt_ip *ip,
-                void *matchinfo,
-                unsigned int matchsize,
-                unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_state_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ipt_match state_match = {
-       .name           = "state",
-       .match          = &match,
-       .checkentry     = &check,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       need_ip_conntrack();
-       return ipt_register_match(&state_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&state_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_string.c b/net/ipv4/netfilter/ipt_string.c
deleted file mode 100644 (file)
index b5def20..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* String matching match for iptables
- * 
- * (C) 2005 Pablo Neira Ayuso <pablo@eurodev.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/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv4/ipt_string.h>
-#include <linux/textsearch.h>
-
-MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>");
-MODULE_DESCRIPTION("IP tables string match module");
-MODULE_LICENSE("GPL");
-
-static int match(const struct sk_buff *skb,
-                const struct net_device *in,
-                const struct net_device *out,
-                const void *matchinfo,
-                int offset,
-                int *hotdrop)
-{
-       struct ts_state state;
-       struct ipt_string_info *conf = (struct ipt_string_info *) matchinfo;
-
-       memset(&state, 0, sizeof(struct ts_state));
-
-       return (skb_find_text((struct sk_buff *)skb, conf->from_offset, 
-                            conf->to_offset, conf->config, &state) 
-                            != UINT_MAX) && !conf->invert;
-}
-
-#define STRING_TEXT_PRIV(m) ((struct ipt_string_info *) m)
-
-static int checkentry(const char *tablename,
-                     const struct ipt_ip *ip,
-                     void *matchinfo,
-                     unsigned int matchsize,
-                     unsigned int hook_mask)
-{
-       struct ipt_string_info *conf = matchinfo;
-       struct ts_config *ts_conf;
-
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info)))
-               return 0;
-
-       /* Damn, can't handle this case properly with iptables... */
-       if (conf->from_offset > conf->to_offset)
-               return 0;
-
-       ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
-                                    GFP_KERNEL, TS_AUTOLOAD);
-       if (IS_ERR(ts_conf))
-               return 0;
-
-       conf->config = ts_conf;
-
-       return 1;
-}
-
-static void destroy(void *matchinfo, unsigned int matchsize)
-{
-       textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
-}
-
-static struct ipt_match string_match = {
-       .name           = "string",
-       .match          = match,
-       .checkentry     = checkentry,
-       .destroy        = destroy,
-       .me             = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&string_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&string_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv4/netfilter/ipt_tcpmss.c b/net/ipv4/netfilter/ipt_tcpmss.c
deleted file mode 100644 (file)
index 4dc9b16..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Kernel module to match TCP MSS values. */
-
-/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
- *
- * 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/skbuff.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter_ipv4/ipt_tcpmss.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-#define TH_SYN 0x02
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("iptables TCP MSS match module");
-
-/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
-static inline int
-mssoption_match(u_int16_t min, u_int16_t max,
-               const struct sk_buff *skb,
-               int invert,
-               int *hotdrop)
-{
-       struct tcphdr _tcph, *th;
-       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-       u8 _opt[15 * 4 - sizeof(_tcph)], *op;
-       unsigned int i, optlen;
-
-       /* If we don't have the whole header, drop packet. */
-       th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
-                               sizeof(_tcph), &_tcph);
-       if (th == NULL)
-               goto dropit;
-
-       /* Malformed. */
-       if (th->doff*4 < sizeof(*th))
-               goto dropit;
-
-       optlen = th->doff*4 - sizeof(*th);
-       if (!optlen)
-               goto out;
-
-       /* Truncated options. */
-       op = skb_header_pointer(skb, skb->nh.iph->ihl * 4 + sizeof(*th),
-                               optlen, _opt);
-       if (op == NULL)
-               goto dropit;
-
-       for (i = 0; i < optlen; ) {
-               if (op[i] == TCPOPT_MSS
-                   && (optlen - i) >= TCPOLEN_MSS
-                   && op[i+1] == TCPOLEN_MSS) {
-                       u_int16_t mssval;
-
-                       mssval = (op[i+2] << 8) | op[i+3];
-                       
-                       return (mssval >= min && mssval <= max) ^ invert;
-               }
-               if (op[i] < 2) i++;
-               else i += op[i+1]?:1;
-       }
-out:
-       return invert;
-
- dropit:
-       *hotdrop = 1;
-       return 0;
-}
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      int *hotdrop)
-{
-       const struct ipt_tcpmss_match_info *info = matchinfo;
-
-       return mssoption_match(info->mss_min, info->mss_max, skb,
-                              info->invert, hotdrop);
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_tcpmss_match_info)))
-               return 0;
-
-       /* Must specify -p tcp */
-       if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
-               printk("tcpmss: Only works on TCP packets\n");
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ipt_match tcpmss_match = {
-       .name           = "tcpmss",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ipt_register_match(&tcpmss_match);
-}
-
-static void __exit fini(void)
-{
-       ipt_unregister_match(&tcpmss_match);
-}
-
-module_init(init);
-module_exit(fini);
index 086a1bb61e3ea8e5b24dd74db3210391da2eab04..9ab765e126f24db8aa5f4cfab815b5a3ddaf1593 100644 (file)
@@ -23,6 +23,7 @@ match(const struct sk_buff *skb,
       const struct net_device *out,
       const void *matchinfo,
       int offset,
+      unsigned int protoff,
       int *hotdrop)
 {
        const struct ipt_tos_info *info = matchinfo;
@@ -32,7 +33,7 @@ match(const struct sk_buff *skb,
 
 static int
 checkentry(const char *tablename,
-           const struct ipt_ip *ip,
+           const void *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
index 219aa9de88cca63c4530075b801e9381f0af67d3..82da53f430ab27d0b35e74220525434876fa5001 100644 (file)
@@ -21,7 +21,7 @@ MODULE_LICENSE("GPL");
 
 static int match(const struct sk_buff *skb, const struct net_device *in,
                 const struct net_device *out, const void *matchinfo,
-                int offset, int *hotdrop)
+                int offset, unsigned int protoff, int *hotdrop)
 {
        const struct ipt_ttl_info *info = matchinfo;
 
@@ -47,7 +47,7 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return 0;
 }
 
-static int checkentry(const char *tablename, const struct ipt_ip *ip,
+static int checkentry(const char *tablename, const void  *ip,
                      void *matchinfo, unsigned int matchsize,
                      unsigned int hook_mask)
 {
index 260a4f0a2a9065b3ae855f678e217739abccae27..212a3079085b2e4ce2d4098c9fc6451be13086b4 100644 (file)
@@ -78,7 +78,8 @@ static struct ipt_table packet_filter = {
        .name           = "filter",
        .valid_hooks    = FILTER_VALID_HOOKS,
        .lock           = RW_LOCK_UNLOCKED,
-       .me             = THIS_MODULE
+       .me             = THIS_MODULE,
+       .af             = AF_INET,
 };
 
 /* The work comes in here from netfilter.c. */
index 160eb11b6e2fa7ff3fde67c0c298e7e2a9ebb721..3212a5cc4b6b0fdbdbd9110dc6cae169042048c6 100644 (file)
@@ -109,6 +109,7 @@ static struct ipt_table packet_mangler = {
        .valid_hooks    = MANGLE_VALID_HOOKS,
        .lock           = RW_LOCK_UNLOCKED,
        .me             = THIS_MODULE,
+       .af             = AF_INET,
 };
 
 /* The work comes in here from netfilter.c. */
index 47449ba83eb9410280a8463b477501d839ff32bb..fdb9e9c81e812b1e1bd785349e6cb13b609a67a7 100644 (file)
@@ -83,7 +83,8 @@ static struct ipt_table packet_raw = {
        .name = "raw", 
        .valid_hooks =  RAW_VALID_HOOKS, 
        .lock = RW_LOCK_UNLOCKED, 
-       .me = THIS_MODULE
+       .me = THIS_MODULE,
+       .af = AF_INET,
 };
 
 /* The work comes in here from netfilter.c. */
index 0c56c52a38317eb7be8f46eb900f2f252501c8ca..167619f638c6543aa50cc76fb1e94fefb2638ebc 100644 (file)
@@ -575,7 +575,7 @@ MODULE_LICENSE("GPL");
 
 static int __init init(void)
 {
-       need_nf_conntrack();
+       need_conntrack();
        return init_or_cleanup(1);
 }
 
@@ -587,9 +587,4 @@ static void __exit fini(void)
 module_init(init);
 module_exit(fini);
 
-void need_ip_conntrack(void)
-{
-}
-
-EXPORT_SYMBOL(need_ip_conntrack);
 EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);
index d23e07fc81facafe1c7a34e10c9a0d5fc75a4168..dbabf81a9b7b4d19389c8d85e3b686026e33dd33 100644 (file)
@@ -42,6 +42,21 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
        x->props.saddr = tmpl->saddr;
        if (x->props.saddr.a4 == 0)
                x->props.saddr.a4 = saddr->a4;
+       if (tmpl->mode && x->props.saddr.a4 == 0) {
+               struct rtable *rt;
+               struct flowi fl_tunnel = {
+                       .nl_u = {
+                               .ip4_u = {
+                                       .daddr = x->id.daddr.a4,
+                               }
+                       }
+               };
+               if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
+                                    &fl_tunnel, AF_INET)) {
+                       x->props.saddr.a4 = rt->rt_src;
+                       dst_release(&rt->u.dst);
+               }
+       }
        x->props.mode = tmpl->mode;
        x->props.reqid = tmpl->reqid;
        x->props.family = AF_INET;
index 7129d423975561c0eb0b3195651929a15c5ea6f8..dfb4f145a139af35f9ef2ebb61723d5ae3edd5d1 100644 (file)
@@ -2644,7 +2644,7 @@ static int if6_seq_show(struct seq_file *seq, void *v)
 {
        struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
        seq_printf(seq,
-                  "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x %02x %8s\n",
+                  NIP6_FMT " %02x %02x %02x %02x %8s\n",
                   NIP6(ifp->addr),
                   ifp->idev->dev->ifindex,
                   ifp->prefix_len,
index 13cc7f89558373994ef23d8cf3dd2d09884c003a..c7932cb420a5c91987fa4034abacee84c1ffb76b 100644 (file)
@@ -332,8 +332,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (!x)
                return;
 
-       NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/"
-                "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+       NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/" NIP6_FMT "\n",
                 ntohl(ah->spi), NIP6(iph->daddr));
 
        xfrm_state_put(x);
index 65e73ac0d6d0d5603c1466d9780058a80a377b95..72bd08af2dfb0ac1c1f1d3fe0fe94cf7cdf9363d 100644 (file)
@@ -532,9 +532,7 @@ static int ac6_seq_show(struct seq_file *seq, void *v)
        struct ac6_iter_state *state = ac6_seq_private(seq);
 
        seq_printf(seq,
-                  "%-4d %-15s "
-                  "%04x%04x%04x%04x%04x%04x%04x%04x "
-                  "%5d\n",
+                  "%-4d %-15s " NIP6_FMT " %5d\n",
                   state->dev->ifindex, state->dev->name,
                   NIP6(im->aca_addr),
                   im->aca_users);
index 6de8ee1a5ad9ec85227d9527b9b1374ca73e8952..7b5b94f13902cbf4ec2ad8ce229ff838ba7fbe0a 100644 (file)
@@ -266,8 +266,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6);
        if (!x)
                return;
-       printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/"
-                       "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 
+       printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/" NIP6_FMT "\n", 
                        ntohl(esph->spi), NIP6(iph->daddr));
        xfrm_state_put(x);
 }
index 53c81fcd20ba23b6573c1525a412f700ba10cccd..fcf883183cefef002c56cdf1e4565b5382ec3ba5 100644 (file)
@@ -607,7 +607,7 @@ static int icmpv6_rcv(struct sk_buff **pskb)
                skb->csum = ~csum_ipv6_magic(saddr, daddr, skb->len,
                                             IPPROTO_ICMPV6, 0);
                if (__skb_checksum_complete(skb)) {
-                       LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
+                       LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [" NIP6_FMT " > " NIP6_FMT "]\n",
                                       NIP6(*saddr), NIP6(*daddr));
                        goto discard_it;
                }
index 964ad9d1276d56f01a47d83eeec3ffb54447ff48..4183c8dac7f6e16c448bd7e74f1f67ab649507fc 100644 (file)
@@ -629,9 +629,7 @@ static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl)
 {
        while(fl) {
                seq_printf(seq,
-                          "%05X %-1d %-6d %-6d %-6ld %-8ld "
-                          "%02x%02x%02x%02x%02x%02x%02x%02x "
-                          "%-4d\n",
+                          "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_FMT " %-4d\n",
                           (unsigned)ntohl(fl->label),
                           fl->share,
                           (unsigned)fl->owner,
@@ -647,8 +645,8 @@ static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl)
 static int ip6fl_seq_show(struct seq_file *seq, void *v)
 {
        if (v == SEQ_START_TOKEN)
-               seq_puts(seq, "Label S Owner  Users  Linger Expires  "
-                             "Dst                              Opt\n");
+               seq_printf(seq, "%-5s %-1s %-6s %-6s %-6s %-8s %-39s %s\n",
+                          "Label", "S", "Owner", "Users", "Linger", "Expires", "Dst", "Opt");
        else
                ip6fl_fl_seq_show(seq, v);
        return 0;
index 626dd39685f2c43675871206fb1d7d360b273359..d511a884dad07504fb73aeb5bf134086aff3c152 100644 (file)
@@ -212,8 +212,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (!x)
                return;
 
-       printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/"
-                       "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+       printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIP6_FMT "\n",
                        spi, NIP6(iph->daddr));
        xfrm_state_put(x);
 }
index cc3e9f5608671d4726816551c9320c80c377d494..0e03eabfb9da3fea0541736e1dc742fb9052de36 100644 (file)
@@ -2373,7 +2373,7 @@ static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
        struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
        seq_printf(seq,
-                  "%-4d %-15s %04x%04x%04x%04x%04x%04x%04x%04x %5d %08X %ld\n", 
+                  "%-4d %-15s " NIP6_FMT " %5d %08X %ld\n", 
                   state->dev->ifindex, state->dev->name,
                   NIP6(im->mca_addr),
                   im->mca_users, im->mca_flags,
@@ -2542,15 +2542,12 @@ static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)
        if (v == SEQ_START_TOKEN) {
                seq_printf(seq, 
                           "%3s %6s "
-                          "%32s %32s %6s %6s\n", "Idx",
+                          "%39s %39s %6s %6s\n", "Idx",
                           "Device", "Multicast Address",
                           "Source Address", "INC", "EXC");
        } else {
                seq_printf(seq,
-                          "%3d %6.6s "
-                          "%04x%04x%04x%04x%04x%04x%04x%04x "
-                          "%04x%04x%04x%04x%04x%04x%04x%04x "
-                          "%6lu %6lu\n",
+                          "%3d %6.6s " NIP6_FMT " " NIP6_FMT " %6lu %6lu\n",
                           state->dev->ifindex, state->dev->name,
                           NIP6(state->im->mca_addr),
                           NIP6(psf->sf_addr),
index 305d9ee6d7dbc3f154f6cb11c2b6a997c25bf0cb..cb8856b1d9518ba251f43fbb5b4ab64ba2bed6da 100644 (file)
@@ -692,7 +692,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
                if (!(neigh->nud_state & NUD_VALID)) {
                        ND_PRINTK1(KERN_DEBUG
                                   "%s(): trying to ucast probe in NUD_INVALID: "
-                                  "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                                  NIP6_FMT "\n",
                                   __FUNCTION__,
                                   NIP6(*target));
                }
index 105dd69ee9fb54cbe4419ffac31a71cf1205f7ed..2d6f8ecbc27bb421ba1ee2513ffd09f3b7c91aae 100644 (file)
@@ -41,6 +41,7 @@ config IP6_NF_QUEUE
 
 config IP6_NF_IPTABLES
        tristate "IP6 tables support (required for filtering/masq/NAT)"
+       depends on NETFILTER_XTABLES
        help
          ip6tables is a general, extensible packet identification framework.
          Currently only the packet filtering and packet mangling subsystem
@@ -50,25 +51,6 @@ config IP6_NF_IPTABLES
          To compile it as a module, choose M here.  If unsure, say N.
 
 # The simple matches.
-config IP6_NF_MATCH_LIMIT
-       tristate "limit match support"
-       depends on IP6_NF_IPTABLES
-       help
-         limit matching allows you to control the rate at which a rule can be
-         matched: mainly useful in combination with the LOG target ("LOG
-         target support", below) and to avoid some Denial of Service attacks.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
-config IP6_NF_MATCH_MAC
-       tristate "MAC address match support"
-       depends on IP6_NF_IPTABLES
-       help
-         mac matching allows you to match packets based on the source
-         Ethernet address of the packet.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_RT
        tristate "Routing header match support"
        depends on IP6_NF_IPTABLES
@@ -124,16 +106,6 @@ config IP6_NF_MATCH_OWNER
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_MARK
-       tristate "netfilter MARK match support"
-       depends on IP6_NF_IPTABLES
-       help
-         Netfilter mark matching allows you to match packets based on the
-         `nfmark' value in the packet.  This can be set by the MARK target
-         (see below).
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_IPV6HEADER
        tristate "IPv6 Extension Headers Match"
        depends on IP6_NF_IPTABLES
@@ -151,15 +123,6 @@ config IP6_NF_MATCH_AHESP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_LENGTH
-       tristate "Packet Length match support"
-       depends on IP6_NF_IPTABLES
-       help
-         This option allows you to match the length of a packet against a
-         specific value or range of values.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_EUI64
        tristate "EUI64 address check"
        depends on IP6_NF_IPTABLES
@@ -170,15 +133,6 @@ config IP6_NF_MATCH_EUI64
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_MATCH_PHYSDEV
-       tristate "Physdev match support"
-       depends on IP6_NF_IPTABLES && BRIDGE_NETFILTER
-       help
-         Physdev packet matching matches against the physical bridge ports
-         the IP packet arrived on or will leave by.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MATCH_POLICY
        tristate "IPsec policy match support"
        depends on IP6_NF_IPTABLES && XFRM
@@ -219,17 +173,6 @@ config IP6_NF_TARGET_REJECT
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_TARGET_NFQUEUE
-       tristate "NFQUEUE Target Support"
-       depends on IP6_NF_IPTABLES
-       help
-         This Target replaced the old obsolete QUEUE target.
-
-         As opposed to QUEUE, it supports 65535 different queues,
-         not just one.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_MANGLE
        tristate "Packet mangling"
        depends on IP6_NF_IPTABLES
@@ -240,19 +183,6 @@ config IP6_NF_MANGLE
 
          To compile it as a module, choose M here.  If unsure, say N.
 
-config IP6_NF_TARGET_MARK
-       tristate "MARK target support"
-       depends on IP6_NF_MANGLE
-       help
-         This option adds a `MARK' target, which allows you to create rules
-         in the `mangle' table which alter the netfilter mark (nfmark) field
-         associated with the packet packet prior to routing. This can change
-         the routing method (see `Use netfilter MARK value as routing
-         key') and can also be used by other subsystems to change their
-         behavior.
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP6_NF_TARGET_HL
        tristate  'HL (hoplimit) target support'
        depends on IP6_NF_MANGLE
index c0c809b426e87f244267103342e612fc1c7fcbe5..663b4749820d7d5e9ffcb955970457e7e7098470 100644 (file)
@@ -4,10 +4,7 @@
 
 # Link order matters here.
 obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
-obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
-obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
-obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
@@ -17,12 +14,9 @@ obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
-obj-$(CONFIG_IP6_NF_MATCH_PHYSDEV) += ip6t_physdev.o
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
-obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
 obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
-obj-$(CONFIG_IP6_NF_TARGET_NFQUEUE) += ip6t_NFQUEUE.o
 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
index 1390370186d975ff1c98bab91d65ee0ca85985b9..847068fd33676cfd3b6bc510be992baf4ab8d06d 100644 (file)
@@ -13,6 +13,9 @@
  *       a table
  * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
  *      - new extension header parser code
+ * 15 Oct 2005 Harald Welte <laforge@netfilter.org>
+ *     - Unification of {ip,ip6}_tables into x_tables
+ *     - Removed tcp and udp code, since it's not ipv6 specific
  */
 
 #include <linux/capability.h>
@@ -23,8 +26,6 @@
 #include <linux/vmalloc.h>
 #include <linux/netdevice.h>
 #include <linux/module.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
 #include <linux/icmpv6.h>
 #include <net/ipv6.h>
 #include <asm/uaccess.h>
@@ -33,6 +34,7 @@
 #include <linux/cpumask.h>
 
 #include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -67,13 +69,8 @@ do {                                                         \
 #else
 #define IP_NF_ASSERT(x)
 #endif
-#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
-static DECLARE_MUTEX(ip6t_mutex);
 
-/* Must have mutex */
-#define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
-#define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
 #include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
@@ -91,30 +88,6 @@ static DECLARE_MUTEX(ip6t_mutex);
 
    Hence the start of any table is given by get_table() below.  */
 
-/* The table itself */
-struct ip6t_table_info
-{
-       /* Size per table */
-       unsigned int size;
-       /* Number of entries: FIXME. --RR */
-       unsigned int number;
-       /* Initial number of entries. Needed for module usage count */
-       unsigned int initial_entries;
-
-       /* Entry points and underflows */
-       unsigned int hook_entry[NF_IP6_NUMHOOKS];
-       unsigned int underflow[NF_IP6_NUMHOOKS];
-
-       /* ip6t_entry tables: one per CPU */
-       void *entries[NR_CPUS];
-};
-
-static LIST_HEAD(ip6t_target);
-static LIST_HEAD(ip6t_match);
-static LIST_HEAD(ip6t_tables);
-#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
-#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
-
 #if 0
 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
 #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
@@ -297,7 +270,7 @@ ip6t_do_table(struct sk_buff **pskb,
              unsigned int hook,
              const struct net_device *in,
              const struct net_device *out,
-             struct ip6t_table *table,
+             struct xt_table *table,
              void *userdata)
 {
        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
@@ -309,6 +282,7 @@ ip6t_do_table(struct sk_buff **pskb,
        const char *indev, *outdev;
        void *table_base;
        struct ip6t_entry *e, *back;
+       struct xt_table_info *private;
 
        /* Initialization */
        indev = in ? in->name : nulldevname;
@@ -321,9 +295,10 @@ ip6t_do_table(struct sk_buff **pskb,
         * match it. */
 
        read_lock_bh(&table->lock);
+       private = table->private;
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
-       table_base = (void *)table->private->entries[smp_processor_id()];
-       e = get_entry(table_base, table->private->hook_entry[hook]);
+       table_base = (void *)private->entries[smp_processor_id()];
+       e = get_entry(table_base, private->hook_entry[hook]);
 
 #ifdef CONFIG_NETFILTER_DEBUG
        /* Check noone else using our table */
@@ -339,7 +314,7 @@ ip6t_do_table(struct sk_buff **pskb,
 #endif
 
        /* For return from builtin chain */
-       back = get_entry(table_base, table->private->underflow[hook]);
+       back = get_entry(table_base, private->underflow[hook]);
 
        do {
                IP_NF_ASSERT(e);
@@ -439,145 +414,6 @@ ip6t_do_table(struct sk_buff **pskb,
 #endif
 }
 
-/*
- * These are weird, but module loading must not be done with mutex
- * held (since they will register), and we have to have a single
- * function to use try_then_request_module().
- */
-
-/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
-static inline struct ip6t_table *find_table_lock(const char *name)
-{
-       struct ip6t_table *t;
-
-       if (down_interruptible(&ip6t_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(t, &ip6t_tables, list)
-               if (strcmp(t->name, name) == 0 && try_module_get(t->me))
-                       return t;
-       up(&ip6t_mutex);
-       return NULL;
-}
-
-/* Find match, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ip6t_match *find_match(const char *name, u8 revision)
-{
-       struct ip6t_match *m;
-       int err = 0;
-
-       if (down_interruptible(&ip6t_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(m, &ip6t_match, list) {
-               if (strcmp(m->name, name) == 0) {
-                       if (m->revision == revision) {
-                               if (try_module_get(m->me)) {
-                                       up(&ip6t_mutex);
-                                       return m;
-                               }
-                       } else
-                               err = -EPROTOTYPE; /* Found something. */
-               }
-       }
-       up(&ip6t_mutex);
-       return ERR_PTR(err);
-}
-
-/* Find target, grabs ref.  Returns ERR_PTR() on error. */
-static inline struct ip6t_target *find_target(const char *name, u8 revision)
-{
-       struct ip6t_target *t;
-       int err = 0;
-
-       if (down_interruptible(&ip6t_mutex) != 0)
-               return ERR_PTR(-EINTR);
-
-       list_for_each_entry(t, &ip6t_target, list) {
-               if (strcmp(t->name, name) == 0) {
-                       if (t->revision == revision) {
-                               if (try_module_get(t->me)) {
-                                       up(&ip6t_mutex);
-                                       return t;
-                               }
-                       } else
-                               err = -EPROTOTYPE; /* Found something. */
-               }
-       }
-       up(&ip6t_mutex);
-       return ERR_PTR(err);
-}
-
-struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
-{
-       struct ip6t_target *target;
-
-       target = try_then_request_module(find_target(name, revision),
-                                        "ip6t_%s", name);
-       if (IS_ERR(target) || !target)
-               return NULL;
-       return target;
-}
-
-static int match_revfn(const char *name, u8 revision, int *bestp)
-{
-       struct ip6t_match *m;
-       int have_rev = 0;
-
-       list_for_each_entry(m, &ip6t_match, list) {
-               if (strcmp(m->name, name) == 0) {
-                       if (m->revision > *bestp)
-                               *bestp = m->revision;
-                       if (m->revision == revision)
-                               have_rev = 1;
-               }
-       }
-       return have_rev;
-}
-
-static int target_revfn(const char *name, u8 revision, int *bestp)
-{
-       struct ip6t_target *t;
-       int have_rev = 0;
-
-       list_for_each_entry(t, &ip6t_target, list) {
-               if (strcmp(t->name, name) == 0) {
-                       if (t->revision > *bestp)
-                               *bestp = t->revision;
-                       if (t->revision == revision)
-                               have_rev = 1;
-               }
-       }
-       return have_rev;
-}
-
-/* Returns true or fals (if no such extension at all) */
-static inline int find_revision(const char *name, u8 revision,
-                               int (*revfn)(const char *, u8, int *),
-                               int *err)
-{
-       int have_rev, best = -1;
-
-       if (down_interruptible(&ip6t_mutex) != 0) {
-               *err = -EINTR;
-               return 1;
-       }
-       have_rev = revfn(name, revision, &best);
-       up(&ip6t_mutex);
-
-       /* Nothing at all?  Return 0 to try loading module. */
-       if (best == -1) {
-               *err = -ENOENT;
-               return 0;
-       }
-
-       *err = best;
-       if (!have_rev)
-               *err = -EPROTONOSUPPORT;
-       return 1;
-}
-
-
 /* All zeroes == unconditional rule. */
 static inline int
 unconditional(const struct ip6t_ip6 *ipv6)
@@ -594,7 +430,7 @@ unconditional(const struct ip6t_ip6 *ipv6)
 /* Figures out from what hook each rule can be called: returns 0 if
    there are loops.  Puts hook bitmask in comefrom. */
 static int
-mark_source_chains(struct ip6t_table_info *newinfo,
+mark_source_chains(struct xt_table_info *newinfo,
                   unsigned int valid_hooks, void *entry0)
 {
        unsigned int hook;
@@ -740,11 +576,11 @@ check_match(struct ip6t_entry_match *m,
 {
        struct ip6t_match *match;
 
-       match = try_then_request_module(find_match(m->u.user.name,
-                                                  m->u.user.revision),
+       match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
+                                       m->u.user.revision),
                                        "ip6t_%s", m->u.user.name);
        if (IS_ERR(match) || !match) {
-               duprintf("check_match: `%s' not found\n", m->u.user.name);
+               duprintf("check_match: `%s' not found\n", m->u.user.name);
                return match ? PTR_ERR(match) : -ENOENT;
        }
        m->u.kernel.match = match;
@@ -785,8 +621,9 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
                goto cleanup_matches;
 
        t = ip6t_get_target(e);
-       target = try_then_request_module(find_target(t->u.user.name,
-                                                    t->u.user.revision),
+       target = try_then_request_module(xt_find_target(AF_INET6,
+                                                       t->u.user.name,
+                                                       t->u.user.revision),
                                         "ip6t_%s", t->u.user.name);
        if (IS_ERR(target) || !target) {
                duprintf("check_entry: `%s' not found\n", t->u.user.name);
@@ -822,7 +659,7 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
 
 static inline int
 check_entry_size_and_hooks(struct ip6t_entry *e,
-                          struct ip6t_table_info *newinfo,
+                          struct xt_table_info *newinfo,
                           unsigned char *base,
                           unsigned char *limit,
                           const unsigned int *hook_entries,
@@ -856,7 +693,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
            < 0 (not IP6T_RETURN). --RR */
 
        /* Clear counters and comefrom */
-       e->counters = ((struct ip6t_counters) { 0, 0 });
+       e->counters = ((struct xt_counters) { 0, 0 });
        e->comefrom = 0;
 
        (*i)++;
@@ -886,7 +723,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i)
 static int
 translate_table(const char *name,
                unsigned int valid_hooks,
-               struct ip6t_table_info *newinfo,
+               struct xt_table_info *newinfo,
                void *entry0,
                unsigned int size,
                unsigned int number,
@@ -963,48 +800,10 @@ translate_table(const char *name,
        return ret;
 }
 
-static struct ip6t_table_info *
-replace_table(struct ip6t_table *table,
-             unsigned int num_counters,
-             struct ip6t_table_info *newinfo,
-             int *error)
-{
-       struct ip6t_table_info *oldinfo;
-
-#ifdef CONFIG_NETFILTER_DEBUG
-       {
-               int cpu;
-
-               for_each_cpu(cpu) {
-                       struct ip6t_entry *table_base = newinfo->entries[cpu];
-                       if (table_base)
-                               table_base->comefrom = 0xdead57ac;
-               }
-       }
-#endif
-
-       /* Do the substitution. */
-       write_lock_bh(&table->lock);
-       /* Check inside lock: is the old number correct? */
-       if (num_counters != table->private->number) {
-               duprintf("num_counters != table->private->number (%u/%u)\n",
-                        num_counters, table->private->number);
-               write_unlock_bh(&table->lock);
-               *error = -EAGAIN;
-               return NULL;
-       }
-       oldinfo = table->private;
-       table->private = newinfo;
-       newinfo->initial_entries = oldinfo->initial_entries;
-       write_unlock_bh(&table->lock);
-
-       return oldinfo;
-}
-
 /* Gets counters. */
 static inline int
 add_entry_to_counter(const struct ip6t_entry *e,
-                    struct ip6t_counters total[],
+                    struct xt_counters total[],
                     unsigned int *i)
 {
        ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
@@ -1025,8 +824,8 @@ set_entry_to_counter(const struct ip6t_entry *e,
 }
 
 static void
-get_counters(const struct ip6t_table_info *t,
-            struct ip6t_counters counters[])
+get_counters(const struct xt_table_info *t,
+            struct xt_counters counters[])
 {
        unsigned int cpu;
        unsigned int i;
@@ -1060,19 +859,20 @@ get_counters(const struct ip6t_table_info *t,
 
 static int
 copy_entries_to_user(unsigned int total_size,
-                    struct ip6t_table *table,
+                    struct xt_table *table,
                     void __user *userptr)
 {
        unsigned int off, num, countersize;
        struct ip6t_entry *e;
-       struct ip6t_counters *counters;
+       struct xt_counters *counters;
+       struct xt_table_info *private = table->private;
        int ret = 0;
        void *loc_cpu_entry;
 
        /* We need atomic snapshot of counters: rest doesn't change
           (other than comefrom, which userspace doesn't care
           about). */
-       countersize = sizeof(struct ip6t_counters) * table->private->number;
+       countersize = sizeof(struct xt_counters) * private->number;
        counters = vmalloc(countersize);
 
        if (counters == NULL)
@@ -1080,11 +880,11 @@ copy_entries_to_user(unsigned int total_size,
 
        /* First, sum counters... */
        write_lock_bh(&table->lock);
-       get_counters(table->private, counters);
+       get_counters(private, counters);
        write_unlock_bh(&table->lock);
 
        /* choose the copy that is on ourc node/cpu */
-       loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
        if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
                ret = -EFAULT;
                goto free_counters;
@@ -1143,87 +943,42 @@ get_entries(const struct ip6t_get_entries *entries,
            struct ip6t_get_entries __user *uptr)
 {
        int ret;
-       struct ip6t_table *t;
+       struct xt_table *t;
 
-       t = find_table_lock(entries->name);
+       t = xt_find_table_lock(AF_INET6, entries->name);
        if (t && !IS_ERR(t)) {
-               duprintf("t->private->number = %u\n",
-                        t->private->number);
-               if (entries->size == t->private->size)
-                       ret = copy_entries_to_user(t->private->size,
+               struct xt_table_info *private = t->private;
+               duprintf("t->private->number = %u\n", private->number);
+               if (entries->size == private->size)
+                       ret = copy_entries_to_user(private->size,
                                                   t, uptr->entrytable);
                else {
                        duprintf("get_entries: I've got %u not %u!\n",
-                                t->private->size,
-                                entries->size);
+                                private->size, entries->size);
                        ret = -EINVAL;
                }
                module_put(t->me);
-               up(&ip6t_mutex);
+               xt_table_unlock(t);
        } else
                ret = t ? PTR_ERR(t) : -ENOENT;
 
        return ret;
 }
 
-static void free_table_info(struct ip6t_table_info *info)
-{
-       int cpu;
-       for_each_cpu(cpu) {
-               if (info->size <= PAGE_SIZE)
-                       kfree(info->entries[cpu]);
-               else
-                       vfree(info->entries[cpu]);
-       }
-       kfree(info);
-}
-
-static struct ip6t_table_info *alloc_table_info(unsigned int size)
-{
-       struct ip6t_table_info *newinfo;
-       int cpu;
-
-       newinfo = kzalloc(sizeof(struct ip6t_table_info), GFP_KERNEL);
-       if (!newinfo)
-               return NULL;
-
-       newinfo->size = size;
-
-       for_each_cpu(cpu) {
-               if (size <= PAGE_SIZE)
-                       newinfo->entries[cpu] = kmalloc_node(size,
-                                                       GFP_KERNEL,
-                                                       cpu_to_node(cpu));
-               else
-                       newinfo->entries[cpu] = vmalloc_node(size,
-                                                            cpu_to_node(cpu));
-               if (newinfo->entries[cpu] == NULL) {
-                       free_table_info(newinfo);
-                       return NULL;
-               }
-       }
-
-       return newinfo;
-}
-
 static int
 do_replace(void __user *user, unsigned int len)
 {
        int ret;
        struct ip6t_replace tmp;
-       struct ip6t_table *t;
-       struct ip6t_table_info *newinfo, *oldinfo;
-       struct ip6t_counters *counters;
+       struct xt_table *t;
+       struct xt_table_info *newinfo, *oldinfo;
+       struct xt_counters *counters;
        void *loc_cpu_entry, *loc_cpu_old_entry;
 
        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
                return -EFAULT;
 
-       /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-       if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
-               return -ENOMEM;
-
-       newinfo = alloc_table_info(tmp.size);
+       newinfo = xt_alloc_table_info(tmp.size);
        if (!newinfo)
                return -ENOMEM;
 
@@ -1235,7 +990,7 @@ do_replace(void __user *user, unsigned int len)
                goto free_newinfo;
        }
 
-       counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
+       counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
        if (!counters) {
                ret = -ENOMEM;
                goto free_newinfo;
@@ -1249,7 +1004,7 @@ do_replace(void __user *user, unsigned int len)
 
        duprintf("ip_tables: Translated table\n");
 
-       t = try_then_request_module(find_table_lock(tmp.name),
+       t = try_then_request_module(xt_find_table_lock(AF_INET6, tmp.name),
                                    "ip6table_%s", tmp.name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1264,7 +1019,7 @@ do_replace(void __user *user, unsigned int len)
                goto put_module;
        }
 
-       oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
+       oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
        if (!oldinfo)
                goto put_module;
 
@@ -1283,23 +1038,23 @@ do_replace(void __user *user, unsigned int len)
        /* Decrease module usage counts and free resource */
        loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
        IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
-       free_table_info(oldinfo);
+       xt_free_table_info(oldinfo);
        if (copy_to_user(tmp.counters, counters,
-                        sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
+                        sizeof(struct xt_counters) * tmp.num_counters) != 0)
                ret = -EFAULT;
        vfree(counters);
-       up(&ip6t_mutex);
+       xt_table_unlock(t);
        return ret;
 
  put_module:
        module_put(t->me);
-       up(&ip6t_mutex);
+       xt_table_unlock(t);
  free_newinfo_counters_untrans:
        IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
  free_newinfo_counters:
        vfree(counters);
  free_newinfo:
-       free_table_info(newinfo);
+       xt_free_table_info(newinfo);
        return ret;
 }
 
@@ -1307,7 +1062,7 @@ do_replace(void __user *user, unsigned int len)
  * and everything is OK. */
 static inline int
 add_counter_to_entry(struct ip6t_entry *e,
-                    const struct ip6t_counters addme[],
+                    const struct xt_counters addme[],
                     unsigned int *i)
 {
 #if 0
@@ -1329,15 +1084,16 @@ static int
 do_add_counters(void __user *user, unsigned int len)
 {
        unsigned int i;
-       struct ip6t_counters_info tmp, *paddc;
-       struct ip6t_table *t;
+       struct xt_counters_info tmp, *paddc;
+       struct xt_table_info *private;
+       struct xt_table *t;
        int ret = 0;
        void *loc_cpu_entry;
 
        if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
                return -EFAULT;
 
-       if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
+       if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
                return -EINVAL;
 
        paddc = vmalloc(len);
@@ -1349,29 +1105,30 @@ do_add_counters(void __user *user, unsigned int len)
                goto free;
        }
 
-       t = find_table_lock(tmp.name);
+       t = xt_find_table_lock(AF_INET6, tmp.name);
        if (!t || IS_ERR(t)) {
                ret = t ? PTR_ERR(t) : -ENOENT;
                goto free;
        }
 
        write_lock_bh(&t->lock);
-       if (t->private->number != paddc->num_counters) {
+       private = t->private;
+       if (private->number != paddc->num_counters) {
                ret = -EINVAL;
                goto unlock_up_free;
        }
 
        i = 0;
        /* Choose the copy that is on our node */
-       loc_cpu_entry = t->private->entries[smp_processor_id()];
+       loc_cpu_entry = private->entries[smp_processor_id()];
        IP6T_ENTRY_ITERATE(loc_cpu_entry,
-                         t->private->size,
+                         private->size,
                          add_counter_to_entry,
                          paddc->counters,
                          &i);
  unlock_up_free:
        write_unlock_bh(&t->lock);
-       up(&ip6t_mutex);
+       xt_table_unlock(t);
        module_put(t->me);
  free:
        vfree(paddc);
@@ -1415,7 +1172,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        switch (cmd) {
        case IP6T_SO_GET_INFO: {
                char name[IP6T_TABLE_MAXNAMELEN];
-               struct ip6t_table *t;
+               struct xt_table *t;
 
                if (*len != sizeof(struct ip6t_getinfo)) {
                        duprintf("length %u != %u\n", *len,
@@ -1430,25 +1187,26 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                }
                name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
 
-               t = try_then_request_module(find_table_lock(name),
+               t = try_then_request_module(xt_find_table_lock(AF_INET6, name),
                                            "ip6table_%s", name);
                if (t && !IS_ERR(t)) {
                        struct ip6t_getinfo info;
+                       struct xt_table_info *private = t->private;
 
                        info.valid_hooks = t->valid_hooks;
-                       memcpy(info.hook_entry, t->private->hook_entry,
+                       memcpy(info.hook_entry, private->hook_entry,
                               sizeof(info.hook_entry));
-                       memcpy(info.underflow, t->private->underflow,
+                       memcpy(info.underflow, private->underflow,
                               sizeof(info.underflow));
-                       info.num_entries = t->private->number;
-                       info.size = t->private->size;
+                       info.num_entries = private->number;
+                       info.size = private->size;
                        memcpy(info.name, name, sizeof(info.name));
 
                        if (copy_to_user(user, &info, *len) != 0)
                                ret = -EFAULT;
                        else
                                ret = 0;
-                       up(&ip6t_mutex);
+                       xt_table_unlock(t);
                        module_put(t->me);
                } else
                        ret = t ? PTR_ERR(t) : -ENOENT;
@@ -1475,7 +1233,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        case IP6T_SO_GET_REVISION_MATCH:
        case IP6T_SO_GET_REVISION_TARGET: {
                struct ip6t_get_revision rev;
-               int (*revfn)(const char *, u8, int *);
+               int target;
 
                if (*len != sizeof(rev)) {
                        ret = -EINVAL;
@@ -1487,12 +1245,13 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
                }
 
                if (cmd == IP6T_SO_GET_REVISION_TARGET)
-                       revfn = target_revfn;
+                       target = 1;
                else
-                       revfn = match_revfn;
+                       target = 0;
 
-               try_then_request_module(find_revision(rev.name, rev.revision,
-                                                     revfn, &ret),
+               try_then_request_module(xt_find_revision(AF_INET6, rev.name,
+                                                        rev.revision,
+                                                        target, &ret),
                                        "ip6t_%s", rev.name);
                break;
        }
@@ -1505,61 +1264,16 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        return ret;
 }
 
-/* Registration hooks for targets. */
-int
-ip6t_register_target(struct ip6t_target *target)
-{
-       int ret;
-
-       ret = down_interruptible(&ip6t_mutex);
-       if (ret != 0)
-               return ret;
-       list_add(&target->list, &ip6t_target);
-       up(&ip6t_mutex);
-       return ret;
-}
-
-void
-ip6t_unregister_target(struct ip6t_target *target)
-{
-       down(&ip6t_mutex);
-       LIST_DELETE(&ip6t_target, target);
-       up(&ip6t_mutex);
-}
-
-int
-ip6t_register_match(struct ip6t_match *match)
-{
-       int ret;
-
-       ret = down_interruptible(&ip6t_mutex);
-       if (ret != 0)
-               return ret;
-
-       list_add(&match->list, &ip6t_match);
-       up(&ip6t_mutex);
-
-       return ret;
-}
-
-void
-ip6t_unregister_match(struct ip6t_match *match)
-{
-       down(&ip6t_mutex);
-       LIST_DELETE(&ip6t_match, match);
-       up(&ip6t_mutex);
-}
-
-int ip6t_register_table(struct ip6t_table *table,
+int ip6t_register_table(struct xt_table *table,
                        const struct ip6t_replace *repl)
 {
        int ret;
-       struct ip6t_table_info *newinfo;
-       static struct ip6t_table_info bootstrap
+       struct xt_table_info *newinfo;
+       static struct xt_table_info bootstrap
                = { 0, 0, 0, { 0 }, { 0 }, { } };
        void *loc_cpu_entry;
 
-       newinfo = alloc_table_info(repl->size);
+       newinfo = xt_alloc_table_info(repl->size);
        if (!newinfo)
                return -ENOMEM;
 
@@ -1573,244 +1287,29 @@ int ip6t_register_table(struct ip6t_table *table,
                              repl->hook_entry,
                              repl->underflow);
        if (ret != 0) {
-               free_table_info(newinfo);
+               xt_free_table_info(newinfo);
                return ret;
        }
 
-       ret = down_interruptible(&ip6t_mutex);
-       if (ret != 0) {
-               free_table_info(newinfo);
+       if (xt_register_table(table, &bootstrap, newinfo) != 0) {
+               xt_free_table_info(newinfo);
                return ret;
        }
 
-       /* Don't autoload: we'd eat our tail... */
-       if (list_named_find(&ip6t_tables, table->name)) {
-               ret = -EEXIST;
-               goto free_unlock;
-       }
-
-       /* Simplifies replace_table code. */
-       table->private = &bootstrap;
-       if (!replace_table(table, 0, newinfo, &ret))
-               goto free_unlock;
-
-       duprintf("table->private->number = %u\n",
-                table->private->number);
-
-       /* save number of initial entries */
-       table->private->initial_entries = table->private->number;
-
-       rwlock_init(&table->lock);
-       list_prepend(&ip6t_tables, table);
-
- unlock:
-       up(&ip6t_mutex);
-       return ret;
-
- free_unlock:
-       free_table_info(newinfo);
-       goto unlock;
+       return 0;
 }
 
-void ip6t_unregister_table(struct ip6t_table *table)
+void ip6t_unregister_table(struct xt_table *table)
 {
+       struct xt_table_info *private;
        void *loc_cpu_entry;
 
-       down(&ip6t_mutex);
-       LIST_DELETE(&ip6t_tables, table);
-       up(&ip6t_mutex);
+       private = xt_unregister_table(table);
 
        /* Decrease module usage counts and free resources */
-       loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
-       IP6T_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
-                         cleanup_entry, NULL);
-       free_table_info(table->private);
-}
-
-/* Returns 1 if the port is matched by the range, 0 otherwise */
-static inline int
-port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
-{
-       int ret;
-
-       ret = (port >= min && port <= max) ^ invert;
-       return ret;
-}
-
-static int
-tcp_find_option(u_int8_t option,
-               const struct sk_buff *skb,
-               unsigned int tcpoff,
-               unsigned int optlen,
-               int invert,
-               int *hotdrop)
-{
-       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
-       u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
-       unsigned int i;
-
-       duprintf("tcp_match: finding option\n");
-       if (!optlen)
-               return invert;
-       /* If we don't have the whole header, drop packet. */
-       op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
-                               _opt);
-       if (op == NULL) {
-               *hotdrop = 1;
-               return 0;
-       }
-
-       for (i = 0; i < optlen; ) {
-               if (op[i] == option) return !invert;
-               if (op[i] < 2) i++;
-               else i += op[i+1]?:1;
-       }
-
-       return invert;
-}
-
-static int
-tcp_match(const struct sk_buff *skb,
-         const struct net_device *in,
-         const struct net_device *out,
-         const void *matchinfo,
-         int offset,
-         unsigned int protoff,
-         int *hotdrop)
-{
-       struct tcphdr _tcph, *th;
-       const struct ip6t_tcp *tcpinfo = matchinfo;
-
-       if (offset) {
-               /* To quote Alan:
-
-                  Don't allow a fragment of TCP 8 bytes in. Nobody normal
-                  causes this. Its a cracker trying to break in by doing a
-                  flag overwrite to pass the direction checks.
-               */
-               if (offset == 1) {
-                       duprintf("Dropping evil TCP offset=1 frag.\n");
-                       *hotdrop = 1;
-               }
-               /* Must not be a fragment. */
-               return 0;
-       }
-
-#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
-
-       th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
-       if (th == NULL) {
-               /* We've been asked to examine this packet, and we
-                  can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil TCP offset=0 tinygram.\n");
-               *hotdrop = 1;
-               return 0;
-       }
-
-       if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
-                       ntohs(th->source),
-                       !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
-               return 0;
-       if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
-                       ntohs(th->dest),
-                       !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
-               return 0;
-       if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
-                     == tcpinfo->flg_cmp,
-                     IP6T_TCP_INV_FLAGS))
-               return 0;
-       if (tcpinfo->option) {
-               if (th->doff * 4 < sizeof(_tcph)) {
-                       *hotdrop = 1;
-                       return 0;
-               }
-               if (!tcp_find_option(tcpinfo->option, skb, protoff,
-                                    th->doff*4 - sizeof(*th),
-                                    tcpinfo->invflags & IP6T_TCP_INV_OPTION,
-                                    hotdrop))
-                       return 0;
-       }
-       return 1;
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-tcp_checkentry(const char *tablename,
-              const struct ip6t_ip6 *ipv6,
-              void *matchinfo,
-              unsigned int matchsize,
-              unsigned int hook_mask)
-{
-       const struct ip6t_tcp *tcpinfo = matchinfo;
-
-       /* Must specify proto == TCP, and no unknown invflags */
-       return ipv6->proto == IPPROTO_TCP
-               && !(ipv6->invflags & IP6T_INV_PROTO)
-               && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
-               && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
-}
-
-static int
-udp_match(const struct sk_buff *skb,
-         const struct net_device *in,
-         const struct net_device *out,
-         const void *matchinfo,
-         int offset,
-         unsigned int protoff,
-         int *hotdrop)
-{
-       struct udphdr _udph, *uh;
-       const struct ip6t_udp *udpinfo = matchinfo;
-
-       /* Must not be a fragment. */
-       if (offset)
-               return 0;
-
-       uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
-       if (uh == NULL) {
-               /* We've been asked to examine this packet, and we
-                  can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil UDP tinygram.\n");
-               *hotdrop = 1;
-               return 0;
-       }
-
-       return port_match(udpinfo->spts[0], udpinfo->spts[1],
-                         ntohs(uh->source),
-                         !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
-               && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
-                             ntohs(uh->dest),
-                             !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-udp_checkentry(const char *tablename,
-              const struct ip6t_ip6 *ipv6,
-              void *matchinfo,
-              unsigned int matchinfosize,
-              unsigned int hook_mask)
-{
-       const struct ip6t_udp *udpinfo = matchinfo;
-
-       /* Must specify proto == UDP, and no unknown invflags */
-       if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
-               duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
-                        IPPROTO_UDP);
-               return 0;
-       }
-       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
-               duprintf("ip6t_udp: matchsize %u != %u\n",
-                        matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
-               return 0;
-       }
-       if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
-               duprintf("ip6t_udp: unknown flags %X\n",
-                        udpinfo->invflags);
-               return 0;
-       }
-
-       return 1;
+       loc_cpu_entry = private->entries[raw_smp_processor_id()];
+       IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
+       xt_free_table_info(private);
 }
 
 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
@@ -1858,11 +1357,12 @@ icmp6_match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 icmp6_checkentry(const char *tablename,
-          const struct ip6t_ip6 *ipv6,
+          const void *entry,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
+       const struct ip6t_ip6 *ipv6 = entry;
        const struct ip6t_icmp *icmpinfo = matchinfo;
 
        /* Must specify proto == ICMP, and no unknown invflags */
@@ -1892,164 +1392,42 @@ static struct nf_sockopt_ops ip6t_sockopts = {
        .get            = do_ip6t_get_ctl,
 };
 
-static struct ip6t_match tcp_matchstruct = {
-       .name           = "tcp",
-       .match          = &tcp_match,
-       .checkentry     = &tcp_checkentry,
-};
-
-static struct ip6t_match udp_matchstruct = {
-       .name           = "udp",
-       .match          = &udp_match,
-       .checkentry     = &udp_checkentry,
-};
-
 static struct ip6t_match icmp6_matchstruct = {
        .name           = "icmp6",
        .match          = &icmp6_match,
        .checkentry     = &icmp6_checkentry,
 };
 
-#ifdef CONFIG_PROC_FS
-static inline int print_name(const char *i,
-                            off_t start_offset, char *buffer, int length,
-                            off_t *pos, unsigned int *count)
-{
-       if ((*count)++ >= start_offset) {
-               unsigned int namelen;
-
-               namelen = sprintf(buffer + *pos, "%s\n",
-                                 i + sizeof(struct list_head));
-               if (*pos + namelen > length) {
-                       /* Stop iterating */
-                       return 1;
-               }
-               *pos += namelen;
-       }
-       return 0;
-}
-
-static inline int print_target(const struct ip6t_target *t,
-                               off_t start_offset, char *buffer, int length,
-                               off_t *pos, unsigned int *count)
-{
-       if (t == &ip6t_standard_target || t == &ip6t_error_target)
-               return 0;
-       return print_name((char *)t, start_offset, buffer, length, pos, count);
-}
-
-static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&ip6t_mutex) != 0)
-               return 0;
-
-       LIST_FIND(&ip6t_tables, print_name, char *,
-                 offset, buffer, length, &pos, &count);
-
-       up(&ip6t_mutex);
-
-       /* `start' hack - see fs/proc/generic.c line ~105 */
-       *start=(char *)((unsigned long)count-offset);
-       return pos;
-}
-
-static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&ip6t_mutex) != 0)
-               return 0;
-
-       LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
-                 offset, buffer, length, &pos, &count);
-
-       up(&ip6t_mutex);
-
-       *start = (char *)((unsigned long)count - offset);
-       return pos;
-}
-
-static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos = 0;
-       unsigned int count = 0;
-
-       if (down_interruptible(&ip6t_mutex) != 0)
-               return 0;
-
-       LIST_FIND(&ip6t_match, print_name, char *,
-                 offset, buffer, length, &pos, &count);
-
-       up(&ip6t_mutex);
-
-       *start = (char *)((unsigned long)count - offset);
-       return pos;
-}
-
-static const struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
-{ { "ip6_tables_names", ip6t_get_tables },
-  { "ip6_tables_targets", ip6t_get_targets },
-  { "ip6_tables_matches", ip6t_get_matches },
-  { NULL, NULL} };
-#endif /*CONFIG_PROC_FS*/
-
 static int __init init(void)
 {
        int ret;
 
+       xt_proto_init(AF_INET6);
+
        /* Noone else will be downing sem now, so we won't sleep */
-       down(&ip6t_mutex);
-       list_append(&ip6t_target, &ip6t_standard_target);
-       list_append(&ip6t_target, &ip6t_error_target);
-       list_append(&ip6t_match, &tcp_matchstruct);
-       list_append(&ip6t_match, &udp_matchstruct);
-       list_append(&ip6t_match, &icmp6_matchstruct);
-       up(&ip6t_mutex);
+       xt_register_target(AF_INET6, &ip6t_standard_target);
+       xt_register_target(AF_INET6, &ip6t_error_target);
+       xt_register_match(AF_INET6, &icmp6_matchstruct);
 
        /* Register setsockopt */
        ret = nf_register_sockopt(&ip6t_sockopts);
        if (ret < 0) {
                duprintf("Unable to register sockopts.\n");
+               xt_proto_fini(AF_INET6);
                return ret;
        }
 
-#ifdef CONFIG_PROC_FS
-       {
-               struct proc_dir_entry *proc;
-               int i;
-
-               for (i = 0; ip6t_proc_entry[i].name; i++) {
-                       proc = proc_net_create(ip6t_proc_entry[i].name, 0,
-                                              ip6t_proc_entry[i].get_info);
-                       if (!proc) {
-                               while (--i >= 0)
-                                      proc_net_remove(ip6t_proc_entry[i].name);
-                               nf_unregister_sockopt(&ip6t_sockopts);
-                               return -ENOMEM;
-                       }
-                       proc->owner = THIS_MODULE;
-               }
-       }
-#endif
-
-       printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
+       printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
        return 0;
 }
 
 static void __exit fini(void)
 {
        nf_unregister_sockopt(&ip6t_sockopts);
-#ifdef CONFIG_PROC_FS
-       {
-               int i;
-               for (i = 0; ip6t_proc_entry[i].name; i++)
-                       proc_net_remove(ip6t_proc_entry[i].name);
-       }
-#endif
+       xt_unregister_match(AF_INET6, &icmp6_matchstruct);
+       xt_unregister_target(AF_INET6, &ip6t_error_target);
+       xt_unregister_target(AF_INET6, &ip6t_standard_target);
+       xt_proto_fini(AF_INET6);
 }
 
 /*
@@ -2128,10 +1506,6 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
 EXPORT_SYMBOL(ip6t_register_table);
 EXPORT_SYMBOL(ip6t_unregister_table);
 EXPORT_SYMBOL(ip6t_do_table);
-EXPORT_SYMBOL(ip6t_register_match);
-EXPORT_SYMBOL(ip6t_unregister_match);
-EXPORT_SYMBOL(ip6t_register_target);
-EXPORT_SYMBOL(ip6t_unregister_target);
 EXPORT_SYMBOL(ip6t_ext_hdr);
 EXPORT_SYMBOL(ipv6_find_hdr);
 EXPORT_SYMBOL(ip6_masked_addrcmp);
index 8f5549b72720ee13e63ded8ab72153e18474321b..306200c3505788fd8675c5c4a8bdd839f0ff6cc0 100644 (file)
@@ -62,7 +62,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
 }
 
 static int ip6t_hl_checkentry(const char *tablename,
-               const struct ip6t_entry *e,
+               const void *entry,
                void *targinfo,
                unsigned int targinfosize,
                unsigned int hook_mask)
index ae4653bfd65462fe31340bf6cf46324d8cf93385..77c725832decdbfc28b1108f9912cae8b09965dd 100644 (file)
@@ -63,9 +63,8 @@ static void dump_packet(const struct nf_loginfo *info,
                return;
        }
 
-       /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000" */
-       printk("SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->saddr));
-       printk("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ih->daddr));
+       /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
+       printk("SRC=" NIP6_FMT " DST=" NIP6_FMT " ", NIP6(ih->saddr), NIP6(ih->daddr));
 
        /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
        printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
@@ -444,7 +443,7 @@ ip6t_log_target(struct sk_buff **pskb,
 
 
 static int ip6t_log_checkentry(const char *tablename,
-                              const struct ip6t_entry *e,
+                              const void *entry,
                               void *targinfo,
                               unsigned int targinfosize,
                               unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c
deleted file mode 100644 (file)
index eab8fb8..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* This is a module which is used for setting the NFMARK field of an skb. */
-
-/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *
- * 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/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_MARK.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-       const struct ip6t_mark_target_info *markinfo = targinfo;
-
-       if((*pskb)->nfmark != markinfo->mark)
-               (*pskb)->nfmark = markinfo->mark;
-
-       return IP6T_CONTINUE;
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ip6t_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_mark_target_info))) {
-               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IP6T_ALIGN(sizeof(struct ip6t_mark_target_info)));
-               return 0;
-       }
-
-       if (strcmp(tablename, "mangle") != 0) {
-               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ip6t_target ip6t_mark_reg = { 
-       .name           = "MARK",
-       .target         = target,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE
-};
-
-static int __init init(void)
-{
-       printk(KERN_DEBUG "registering ipv6 mark target\n");
-       if (ip6t_register_target(&ip6t_mark_reg))
-               return -EINVAL;
-
-       return 0;
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_target(&ip6t_mark_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_NFQUEUE.c b/net/ipv6/netfilter/ip6t_NFQUEUE.c
deleted file mode 100644 (file)
index c6e3730..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* ip6tables module for using new netfilter netlink queue
- *
- * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
-
-MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables NFQUEUE target");
-MODULE_LICENSE("GPL");
-
-static unsigned int
-target(struct sk_buff **pskb,
-       const struct net_device *in,
-       const struct net_device *out,
-       unsigned int hooknum,
-       const void *targinfo,
-       void *userinfo)
-{
-       const struct ipt_NFQ_info *tinfo = targinfo;
-
-       return NF_QUEUE_NR(tinfo->queuenum);
-}
-
-static int
-checkentry(const char *tablename,
-          const struct ip6t_entry *e,
-           void *targinfo,
-           unsigned int targinfosize,
-           unsigned int hook_mask)
-{
-       if (targinfosize != IP6T_ALIGN(sizeof(struct ipt_NFQ_info))) {
-               printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
-                      targinfosize,
-                      IP6T_ALIGN(sizeof(struct ipt_NFQ_info)));
-               return 0;
-       }
-
-       return 1;
-}
-
-static struct ip6t_target ipt_NFQ_reg = {
-       .name           = "NFQUEUE",
-       .target         = target,
-       .checkentry     = checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ip6t_register_target(&ipt_NFQ_reg);
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_target(&ipt_NFQ_reg);
-}
-
-module_init(init);
-module_exit(fini);
index b03e87adca93c149ef2fbf6f5d22677e0c224f65..c745717b4ce2165d0d8b73a415c4cf229b88df00 100644 (file)
@@ -218,12 +218,13 @@ static unsigned int reject6_target(struct sk_buff **pskb,
 }
 
 static int check(const char *tablename,
-                const struct ip6t_entry *e,
+                const void *entry,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
 {
        const struct ip6t_reject_info *rejinfo = targinfo;
+       const struct ip6t_entry *e = entry;
 
        if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
                DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
index f5c1a7ff4a1f05407ea5cb65f4d5863988f848a6..219a30365dff27dcef63046176e9f8a6ef19d41c 100644 (file)
@@ -98,7 +98,7 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *entry,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
index 48cf5f9efc95c58788044a979db8d7e8466033e7..80fe82669ce2616af5f99e866140dbf50d65a316 100644 (file)
@@ -178,7 +178,7 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *info,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
index e1828f6d0a4061c0ca6e8ae40b084cf9519ef080..724285df87115e5e75e26e99c248ca0cab823dfd 100644 (file)
@@ -76,7 +76,7 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *ip,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
index 616c2cbcd54d297a84e1a933c9b7a28d4c01c006..ddf5f571909c03b27b8038e11af598da276aea6e 100644 (file)
@@ -62,7 +62,7 @@ match(const struct sk_buff *skb,
 
 static int
 ip6t_eui64_checkentry(const char *tablename,
-                  const struct ip6t_ip6 *ip,
+                  const void  *ip,
                   void *matchinfo,
                   unsigned int matchsize,
                   unsigned int hook_mask)
index d1549b268669b7cc990ba322f39ac1726d277db1..a9964b946ed503409eeaa750d044ac82fa654bc3 100644 (file)
@@ -115,7 +115,7 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *ip,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
index e3bc8e2700e77ee5cb03a30955894856f90a3e67..ed8ded18bbd4f5970fadb49f180ef9bd275ea327 100644 (file)
@@ -178,7 +178,7 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *entry,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
index 0beaff5471dd320adbc8be0deb2f43954a0b1ce7..c5d9079f2d9dfc885f764f4984b5e9e8deb8d8b4 100644 (file)
@@ -48,7 +48,7 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
        return 0;
 }
 
-static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
+static int checkentry(const char *tablename, const void *entry,
                      void *matchinfo, unsigned int matchsize,
                      unsigned int hook_mask)
 {
index 32e67f05845b44353758983ed8c5935e6a028dd0..fda1ceaf5a2976c579ef22e7899791561a465bff 100644 (file)
@@ -124,7 +124,7 @@ ipv6header_match(const struct sk_buff *skb,
 
 static int
 ipv6header_checkentry(const char *tablename,
-                     const struct ip6t_ip6 *ip,
+                     const void *ip,
                      void *matchinfo,
                      unsigned int matchsize,
                      unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_length.c b/net/ipv6/netfilter/ip6t_length.c
deleted file mode 100644 (file)
index e0537d3..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Length Match - IPv6 Port */
-
-/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
- *
- * 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/skbuff.h>
-#include <linux/netfilter_ipv6/ip6t_length.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
-MODULE_DESCRIPTION("IPv6 packet length match");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-       const struct ip6t_length_info *info = matchinfo;
-       u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
-       
-       return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ip6t_ip6 *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ip6t_match length_match = {
-       .name           = "length",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ip6t_register_match(&length_match);
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_match(&length_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_limit.c b/net/ipv6/netfilter/ip6t_limit.c
deleted file mode 100644 (file)
index fb782f6..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Kernel module to control the rate
- *
- * 2 September 1999: Changed from the target RATE to the match
- *                   `limit', removed logging.  Did I mention that
- *                   Alexey is a fucking genius?
- *                   Rusty Russell (rusty@rustcorp.com.au).  */
-
-/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
- * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
- *
- * 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/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_limit.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
-MODULE_DESCRIPTION("rate limiting within ip6tables");
-
-/* The algorithm used is the Simple Token Bucket Filter (TBF)
- * see net/sched/sch_tbf.c in the linux source tree
- */
-
-static DEFINE_SPINLOCK(limit_lock);
-
-/* Rusty: This is my (non-mathematically-inclined) understanding of
-   this algorithm.  The `average rate' in jiffies becomes your initial
-   amount of credit `credit' and the most credit you can ever have
-   `credit_cap'.  The `peak rate' becomes the cost of passing the
-   test, `cost'.
-
-   `prev' tracks the last packet hit: you gain one credit per jiffy.
-   If you get credit balance more than this, the extra credit is
-   discarded.  Every time the match passes, you lose `cost' credits;
-   if you don't have that many, the test fails.
-
-   See Alexey's formal explanation in net/sched/sch_tbf.c.
-
-   To avoid underflow, we multiply by 128 (ie. you get 128 credits per
-   jiffy).  Hence a cost of 2^32-1, means one pass per 32768 seconds
-   at 1024HZ (or one every 9 hours).  A cost of 1 means 12800 passes
-   per second at 100HZ.  */
-
-#define CREDITS_PER_JIFFY 128
-
-static int
-ip6t_limit_match(const struct sk_buff *skb,
-               const struct net_device *in,
-               const struct net_device *out,
-               const void *matchinfo,
-               int offset,
-               unsigned int protoff,
-               int *hotdrop)
-{
-       struct ip6t_rateinfo *r = ((struct ip6t_rateinfo *)matchinfo)->master;
-       unsigned long now = jiffies;
-
-       spin_lock_bh(&limit_lock);
-       r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
-       if (r->credit > r->credit_cap)
-               r->credit = r->credit_cap;
-
-       if (r->credit >= r->cost) {
-               /* We're not limited. */
-               r->credit -= r->cost;
-               spin_unlock_bh(&limit_lock);
-               return 1;
-       }
-
-               spin_unlock_bh(&limit_lock);
-       return 0;
-}
-
-/* Precision saver. */
-static u_int32_t
-user2credits(u_int32_t user)
-{
-       /* If multiplying would overflow... */
-       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
-               /* Divide first. */
-               return (user / IP6T_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
-
-       return (user * HZ * CREDITS_PER_JIFFY) / IP6T_LIMIT_SCALE;
-}
-
-static int
-ip6t_limit_checkentry(const char *tablename,
-                    const struct ip6t_ip6 *ip,
-                    void *matchinfo,
-                    unsigned int matchsize,
-                    unsigned int hook_mask)
-{
-       struct ip6t_rateinfo *r = matchinfo;
-
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rateinfo)))
-               return 0;
-
-       /* Check for overflow. */
-       if (r->burst == 0
-           || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-               printk("Call rusty: overflow in ip6t_limit: %u/%u\n",
-                      r->avg, r->burst);
-               return 0;
-       }
-
-       /* User avg in seconds * IP6T_LIMIT_SCALE: convert to jiffies *
-          128. */
-       r->prev = jiffies;
-       r->credit = user2credits(r->avg * r->burst);     /* Credits full. */
-       r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
-       r->cost = user2credits(r->avg);
-
-       /* For SMP, we only want to use one set of counters. */
-       r->master = r;
-
-       return 1;
-}
-
-static struct ip6t_match ip6t_limit_reg = {
-       .name           = "limit",
-       .match          = ip6t_limit_match,
-       .checkentry     = ip6t_limit_checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       if (ip6t_register_match(&ip6t_limit_reg))
-               return -EINVAL;
-       return 0;
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_match(&ip6t_limit_reg);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_mac.c b/net/ipv6/netfilter/ip6t_mac.c
deleted file mode 100644 (file)
index c848152..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Kernel module to match MAC address parameters. */
-
-/* (C) 1999-2001 Paul `Rusty' Russell
- * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.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/skbuff.h>
-#include <linux/if_ether.h>
-#include <linux/etherdevice.h>
-
-#include <linux/netfilter_ipv6/ip6t_mac.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MAC address matching module for IPv6");
-MODULE_AUTHOR("Netfilter Core Teaam <coreteam@netfilter.org>");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-    const struct ip6t_mac_info *info = matchinfo;
-
-    /* Is mac pointer valid? */
-    return (skb->mac.raw >= skb->head
-           && (skb->mac.raw + ETH_HLEN) <= skb->data
-           /* If so, compare... */
-           && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
-               ^ info->invert));
-}
-
-static int
-ip6t_mac_checkentry(const char *tablename,
-                  const struct ip6t_ip6 *ip,
-                  void *matchinfo,
-                  unsigned int matchsize,
-                  unsigned int hook_mask)
-{
-       if (hook_mask
-           & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN)
-               | (1 << NF_IP6_FORWARD))) {
-               printk("ip6t_mac: only valid for PRE_ROUTING, LOCAL_IN or"
-                      " FORWARD\n");
-               return 0;
-       }
-
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_mac_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ip6t_match mac_match = {
-       .name           = "mac",
-       .match          = &match,
-       .checkentry     = &ip6t_mac_checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ip6t_register_match(&mac_match);
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_match(&mac_match);
-}
-
-module_init(init);
-module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_mark.c b/net/ipv6/netfilter/ip6t_mark.c
deleted file mode 100644 (file)
index affc3de..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/* Kernel module to match NFMARK values. */
-
-/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *
- * 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/skbuff.h>
-
-#include <linux/netfilter_ipv6/ip6t_mark.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables mark match");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-       const struct ip6t_mark_info *info = matchinfo;
-
-       return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ip6t_ip6 *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_mark_info)))
-               return 0;
-
-       return 1;
-}
-
-static struct ip6t_match mark_match = {
-       .name           = "mark",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ip6t_register_match(&mark_match);
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_match(&mark_match);
-}
-
-module_init(init);
-module_exit(fini);
index 6e3246153fa37c6cfebf79f77f2d5990b3a3bee7..49f7829dfbc2343db16fd8f343a848cf97d61a72 100644 (file)
@@ -84,11 +84,12 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *info,
           void *matchinfo,
           unsigned int matchsize,
           unsigned int hook_mask)
 {
+       const struct ip6t_ip6 *ip = info;
        const struct ip6t_multiport *multiinfo = matchinfo;
 
        if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
index 4de4cdad4b7d281522aeb34ca813f9db5c4fa7c0..5409b375b5121efbc3eea1ede04c7e80bafc471d 100644 (file)
@@ -53,7 +53,7 @@ match(const struct sk_buff *skb,
 
 static int
 checkentry(const char *tablename,
-           const struct ip6t_ip6 *ip,
+           const void  *ip,
            void *matchinfo,
            unsigned int matchsize,
            unsigned int hook_mask)
diff --git a/net/ipv6/netfilter/ip6t_physdev.c b/net/ipv6/netfilter/ip6t_physdev.c
deleted file mode 100644 (file)
index 71515c8..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Kernel module to match the bridge port in and
- * out device for IP packets coming into contact with a bridge. */
-
-/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
- *
- * 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/skbuff.h>
-#include <linux/netfilter_ipv6/ip6t_physdev.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_bridge.h>
-#define MATCH   1
-#define NOMATCH 0
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
-MODULE_DESCRIPTION("iptables bridge physical device match module");
-
-static int
-match(const struct sk_buff *skb,
-      const struct net_device *in,
-      const struct net_device *out,
-      const void *matchinfo,
-      int offset,
-      unsigned int protoff,
-      int *hotdrop)
-{
-       int i;
-       static const char nulldevname[IFNAMSIZ];
-       const struct ip6t_physdev_info *info = matchinfo;
-       unsigned int ret;
-       const char *indev, *outdev;
-       struct nf_bridge_info *nf_bridge;
-
-       /* Not a bridged IP packet or no info available yet:
-        * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
-        * the destination device will be a bridge. */
-       if (!(nf_bridge = skb->nf_bridge)) {
-               /* Return MATCH if the invert flags of the used options are on */
-               if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) &&
-                   !(info->invert & IP6T_PHYSDEV_OP_BRIDGED))
-                       return NOMATCH;
-               if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN) &&
-                   !(info->invert & IP6T_PHYSDEV_OP_ISIN))
-                       return NOMATCH;
-               if ((info->bitmask & IP6T_PHYSDEV_OP_ISOUT) &&
-                   !(info->invert & IP6T_PHYSDEV_OP_ISOUT))
-                       return NOMATCH;
-               if ((info->bitmask & IP6T_PHYSDEV_OP_IN) &&
-                   !(info->invert & IP6T_PHYSDEV_OP_IN))
-                       return NOMATCH;
-               if ((info->bitmask & IP6T_PHYSDEV_OP_OUT) &&
-                   !(info->invert & IP6T_PHYSDEV_OP_OUT))
-                       return NOMATCH;
-               return MATCH;
-       }
-
-       /* This only makes sense in the FORWARD and POSTROUTING chains */
-       if ((info->bitmask & IP6T_PHYSDEV_OP_BRIDGED) &&
-           (!!(nf_bridge->mask & BRNF_BRIDGED) ^
-           !(info->invert & IP6T_PHYSDEV_OP_BRIDGED)))
-               return NOMATCH;
-
-       if ((info->bitmask & IP6T_PHYSDEV_OP_ISIN &&
-           (!nf_bridge->physindev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISIN))) ||
-           (info->bitmask & IP6T_PHYSDEV_OP_ISOUT &&
-           (!nf_bridge->physoutdev ^ !!(info->invert & IP6T_PHYSDEV_OP_ISOUT))))
-               return NOMATCH;
-
-       if (!(info->bitmask & IP6T_PHYSDEV_OP_IN))
-               goto match_outdev;
-       indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
-       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-               ret |= (((const unsigned int *)indev)[i]
-                       ^ ((const unsigned int *)info->physindev)[i])
-                       & ((const unsigned int *)info->in_mask)[i];
-       }
-
-       if ((ret == 0) ^ !(info->invert & IP6T_PHYSDEV_OP_IN))
-               return NOMATCH;
-
-match_outdev:
-       if (!(info->bitmask & IP6T_PHYSDEV_OP_OUT))
-               return MATCH;
-       outdev = nf_bridge->physoutdev ?
-                nf_bridge->physoutdev->name : nulldevname;
-       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
-               ret |= (((const unsigned int *)outdev)[i]
-                       ^ ((const unsigned int *)info->physoutdev)[i])
-                       & ((const unsigned int *)info->out_mask)[i];
-       }
-
-       return (ret != 0) ^ !(info->invert & IP6T_PHYSDEV_OP_OUT);
-}
-
-static int
-checkentry(const char *tablename,
-                      const struct ip6t_ip6 *ip,
-                      void *matchinfo,
-                      unsigned int matchsize,
-                      unsigned int hook_mask)
-{
-       const struct ip6t_physdev_info *info = matchinfo;
-
-       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_physdev_info)))
-               return 0;
-       if (!(info->bitmask & IP6T_PHYSDEV_OP_MASK) ||
-           info->bitmask & ~IP6T_PHYSDEV_OP_MASK)
-               return 0;
-       return 1;
-}
-
-static struct ip6t_match physdev_match = {
-       .name           = "physdev",
-       .match          = &match,
-       .checkentry     = &checkentry,
-       .me             = THIS_MODULE,
-};
-
-static int __init init(void)
-{
-       return ip6t_register_match(&physdev_match);
-}
-
-static void __exit fini(void)
-{
-       ip6t_unregister_match(&physdev_match);
-}
-
-module_init(init);
-module_exit(fini);
index c1e770e45543b3c749debf6b02c0f4444e0f4323..8465b4375855862f7f196ce260b0a64ef2d61343 100644 (file)
@@ -183,7 +183,7 @@ match(const struct sk_buff *skb,
 /* Called when user tries to insert an entry of this type. */
 static int
 checkentry(const char *tablename,
-          const struct ip6t_ip6 *ip,
+          const void *entry,
           void *matchinfo,
           unsigned int matchinfosize,
           unsigned int hook_mask)
index 4c0028671c20f0987c79747532ef5f4b14d87997..ce4a968e1f7067ec18dd4c69657b0b3feabbcdc9 100644 (file)
@@ -97,6 +97,7 @@ static struct ip6t_table packet_filter = {
        .valid_hooks    = FILTER_VALID_HOOKS,
        .lock           = RW_LOCK_UNLOCKED,
        .me             = THIS_MODULE,
+       .af             = AF_INET6,
 };
 
 /* The work comes in here from netfilter.c. */
index 85c1e6eada1911e8555b604d1dc1ffdcb95a0255..30a4627e000d43c97fcc8cb66395775d2744d495 100644 (file)
@@ -127,6 +127,7 @@ static struct ip6t_table packet_mangler = {
        .valid_hooks    = MANGLE_VALID_HOOKS,
        .lock           = RW_LOCK_UNLOCKED,
        .me             = THIS_MODULE,
+       .af             = AF_INET6,
 };
 
 /* The work comes in here from netfilter.c. */
index c2982efd14afd0fb47d7363c71f06a4d1374e848..db28ba3855e2a46af5de28ec31de58f2a86e3512 100644 (file)
@@ -106,11 +106,12 @@ static struct
        }
 };
 
-static struct ip6t_table packet_raw = { 
+static struct xt_table packet_raw = { 
        .name = "raw", 
        .valid_hooks = RAW_VALID_HOOKS, 
        .lock = RW_LOCK_UNLOCKED, 
-       .me = THIS_MODULE
+       .me = THIS_MODULE,
+       .af = AF_INET6,
 };
 
 /* The work comes in here from netfilter.c. */
index e57d6fc9957aee298a0a984c7ca4201246bb6e77..ac702a29dd160a0cd2bcc774d24aae1e6f0a8f62 100644 (file)
@@ -74,7 +74,7 @@ static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
 static int ipv6_print_tuple(struct seq_file *s,
                            const struct nf_conntrack_tuple *tuple)
 {
-       return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ",
+       return seq_printf(s, "src=" NIP6_FMT " dst=" NIP6_FMT " ",
                          NIP6(*((struct in6_addr *)tuple->src.u3.ip6)),
                          NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));
 }
@@ -584,7 +584,7 @@ MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
 
 static int __init init(void)
 {
-       need_nf_conntrack();
+       need_conntrack();
        return init_or_cleanup(1);
 }
 
@@ -595,9 +595,3 @@ static void __exit fini(void)
 
 module_init(init);
 module_exit(fini);
-
-void need_ip6_conntrack(void)
-{
-}
-
-EXPORT_SYMBOL(need_ip6_conntrack);
index f3e5ffbd592f9ee4c3bd04c661453fe6ccda64d5..84ef9a13108d3190ccae6b2c4174219b3c3d2d61 100644 (file)
@@ -70,8 +70,8 @@ struct nf_ct_frag6_skb_cb
 
 struct nf_ct_frag6_queue
 {
-       struct nf_ct_frag6_queue        *next;
-       struct list_head lru_list;              /* lru list member      */
+       struct hlist_node       list;
+       struct list_head        lru_list;       /* lru list member      */
 
        __u32                   id;             /* fragment id          */
        struct in6_addr         saddr;
@@ -90,14 +90,13 @@ struct nf_ct_frag6_queue
 #define FIRST_IN               2
 #define LAST_IN                        1
        __u16                   nhoffset;
-       struct nf_ct_frag6_queue        **pprev;
 };
 
 /* Hash table. */
 
 #define FRAG6Q_HASHSZ  64
 
-static struct nf_ct_frag6_queue *nf_ct_frag6_hash[FRAG6Q_HASHSZ];
+static struct hlist_head nf_ct_frag6_hash[FRAG6Q_HASHSZ];
 static DEFINE_RWLOCK(nf_ct_frag6_lock);
 static u32 nf_ct_frag6_hash_rnd;
 static LIST_HEAD(nf_ct_frag6_lru_list);
@@ -105,9 +104,7 @@ int nf_ct_frag6_nqueues = 0;
 
 static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
 {
-       if (fq->next)
-               fq->next->pprev = fq->pprev;
-       *fq->pprev = fq->next;
+       hlist_del(&fq->list);
        list_del(&fq->lru_list);
        nf_ct_frag6_nqueues--;
 }
@@ -158,28 +155,18 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
        get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32));
        for (i = 0; i < FRAG6Q_HASHSZ; i++) {
                struct nf_ct_frag6_queue *q;
+               struct hlist_node *p, *n;
 
-               q = nf_ct_frag6_hash[i];
-               while (q) {
-                       struct nf_ct_frag6_queue *next = q->next;
+               hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], list) {
                        unsigned int hval = ip6qhashfn(q->id,
                                                       &q->saddr,
                                                       &q->daddr);
-
                        if (hval != i) {
-                               /* Unlink. */
-                               if (q->next)
-                                       q->next->pprev = q->pprev;
-                               *q->pprev = q->next;
-
+                               hlist_del(&q->list);
                                /* Relink to new hash chain. */
-                               if ((q->next = nf_ct_frag6_hash[hval]) != NULL)
-                                       q->next->pprev = &q->next;
-                               nf_ct_frag6_hash[hval] = q;
-                               q->pprev = &nf_ct_frag6_hash[hval];
+                               hlist_add_head(&q->list,
+                                              &nf_ct_frag6_hash[hval]);
                        }
-
-                       q = next;
                }
        }
        write_unlock(&nf_ct_frag6_lock);
@@ -314,15 +301,17 @@ out:
 
 /* Creation primitives. */
 
-
 static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
                                          struct nf_ct_frag6_queue *fq_in)
 {
        struct nf_ct_frag6_queue *fq;
+#ifdef CONFIG_SMP
+       struct hlist_node *n;
+#endif
 
        write_lock(&nf_ct_frag6_lock);
 #ifdef CONFIG_SMP
-       for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+       hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
                if (fq->id == fq_in->id && 
                    !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) &&
                    !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) {
@@ -340,10 +329,7 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
                atomic_inc(&fq->refcnt);
 
        atomic_inc(&fq->refcnt);
-       if ((fq->next = nf_ct_frag6_hash[hash]) != NULL)
-               fq->next->pprev = &fq->next;
-       nf_ct_frag6_hash[hash] = fq;
-       fq->pprev = &nf_ct_frag6_hash[hash];
+       hlist_add_head(&fq->list, &nf_ct_frag6_hash[hash]);
        INIT_LIST_HEAD(&fq->lru_list);
        list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
        nf_ct_frag6_nqueues++;
@@ -384,10 +370,11 @@ static __inline__ struct nf_ct_frag6_queue *
 fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
 {
        struct nf_ct_frag6_queue *fq;
+       struct hlist_node *n;
        unsigned int hash = ip6qhashfn(id, src, dst);
 
        read_lock(&nf_ct_frag6_lock);
-       for (fq = nf_ct_frag6_hash[hash]; fq; fq = fq->next) {
+       hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
                if (fq->id == id && 
                    !ipv6_addr_cmp(src, &fq->saddr) &&
                    !ipv6_addr_cmp(dst, &fq->daddr)) {
index bf0d0abc3871b64cccd967f881febcfd0b298396..a5723024d3b372d8df6503cd05e6cfde488fc79e 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pfkeyv2.h>
 #include <linux/ipsec.h>
 #include <net/ipv6.h>
+#include <net/addrconf.h>
 
 static struct xfrm_state_afinfo xfrm6_state_afinfo;
 
@@ -41,6 +42,22 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
        memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr));
        if (ipv6_addr_any((struct in6_addr*)&x->props.saddr))
                memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr));
+       if (tmpl->mode && ipv6_addr_any((struct in6_addr*)&x->props.saddr)) {
+               struct rt6_info *rt;
+               struct flowi fl_tunnel = {
+                       .nl_u = {
+                               .ip6_u = {
+                                       .daddr = *(struct in6_addr *)daddr,
+                               }
+                       }
+               };
+               if (!xfrm_dst_lookup((struct xfrm_dst **)&rt,
+                                    &fl_tunnel, AF_INET6)) {
+                       ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)daddr,
+                                      (struct in6_addr *)&x->props.saddr);
+                       dst_release(&rt->u.dst);
+               }
+       }
        x->props.mode = tmpl->mode;
        x->props.reqid = tmpl->reqid;
        x->props.family = AF_INET6;
index da09ff258648e0be62dbf09e953c4b836edb9c1e..8cfc58b96fc2553cbb946765a70c8c6932ba0cff 100644 (file)
@@ -259,8 +259,7 @@ try_next_2:;
        spi = 0;
        goto out;
 alloc_spi:
-       X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for "
-                             "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", 
+       X6TPRINTK3(KERN_DEBUG "%s(): allocate new spi for " NIP6_FMT "\n",
                              __FUNCTION__, 
                              NIP6(*(struct in6_addr *)saddr));
        x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, SLAB_ATOMIC);
@@ -323,9 +322,8 @@ void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
                                  list_byaddr)
        {
                if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
-                       X6TPRINTK3(KERN_DEBUG "%s(): x6spi object "
-                                             "for %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-                                             "found at %p\n",
+                       X6TPRINTK3(KERN_DEBUG "%s(): x6spi object for " NIP6_FMT 
+                                             " found at %p\n",
                                   __FUNCTION__, 
                                   NIP6(*(struct in6_addr *)saddr),
                                   x6spi);
index 7d55f9cbd853670688a58613e7bdbb7a0731c9e0..99c0a0fa4a978744258a221321c1d4fa2f6ef39c 100644 (file)
@@ -103,3 +103,261 @@ config NF_CT_NETLINK
          This option enables support for a netlink-based userspace interface
 
 endmenu
+
+config NETFILTER_XTABLES
+       tristate "Netfilter Xtables support (required for ip_tables)"
+       help
+         This is required if you intend to use any of ip_tables,
+         ip6_tables or arp_tables.
+
+# alphabetically ordered list of targets
+
+config NETFILTER_XT_TARGET_CLASSIFY
+       tristate '"CLASSIFY" target support'
+       depends on NETFILTER_XTABLES
+       help
+         This option adds a `CLASSIFY' target, which enables the user to set
+         the priority of a packet. Some qdiscs can use this value for
+         classification, among these are:
+
+         atm, cbq, dsmark, pfifo_fast, htb, prio
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_TARGET_CONNMARK
+       tristate  '"CONNMARK" target support'
+       depends on NETFILTER_XTABLES
+       depends on IP_NF_MANGLE || IP6_NF_MANGLE
+       depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
+       help
+         This option adds a `CONNMARK' target, which allows one to manipulate
+         the connection mark value.  Similar to the MARK target, but
+         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'.
+
+config NETFILTER_XT_TARGET_MARK
+       tristate '"MARK" target support'
+       depends on NETFILTER_XTABLES
+       help
+         This option adds a `MARK' target, which allows you to create rules
+         in the `mangle' table which alter the netfilter mark (nfmark) field
+         associated with the packet prior to routing. This can change
+         the routing method (see `Use netfilter MARK value as routing
+         key') and can also be used by other subsystems to change their
+         behavior.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_TARGET_NFQUEUE
+       tristate '"NFQUEUE" target Support'
+       depends on NETFILTER_XTABLES
+       help
+         This Target replaced the old obsolete QUEUE target.
+
+         As opposed to QUEUE, it supports 65535 different queues,
+         not just one.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_TARGET_NOTRACK
+       tristate  '"NOTRACK" target support'
+       depends on NETFILTER_XTABLES
+       depends on IP_NF_RAW || IP6_NF_RAW
+       depends on IP_NF_CONNTRACK || NF_CONNTRACK
+       help
+         The NOTRACK target allows a select rule to specify
+         which packets *not* to enter the conntrack/NAT
+         subsystem with all the consequences (no ICMP error tracking,
+         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'.
+
+config NETFILTER_XT_MATCH_COMMENT
+       tristate  '"comment" match support'
+       depends on NETFILTER_XTABLES
+       help
+         This option adds a `comment' dummy-match, which allows you to put
+         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'.
+
+config NETFILTER_XT_MATCH_CONNBYTES
+       tristate  '"connbytes" per-connection counter match support'
+       depends on NETFILTER_XTABLES
+       depends on (IP_NF_CONNTRACK && IP_NF_CT_ACCT) || NF_CT_ACCT
+       help
+         This option adds a `connbytes' match, which allows you to match the
+         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'.
+
+config NETFILTER_XT_MATCH_CONNMARK
+       tristate  '"connmark" connection mark match support'
+       depends on NETFILTER_XTABLES
+       depends on (IP_NF_CONNTRACK && IP_NF_CONNTRACK_MARK) || NF_CONNTRACK_MARK
+       help
+         This option adds a `connmark' match, which allows you to match the
+         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'.
+
+config NETFILTER_XT_MATCH_CONNTRACK
+       tristate '"conntrack" connection tracking match support'
+       depends on NETFILTER_XTABLES
+       depends on IP_NF_CONNTRACK || NF_CONNTRACK
+       help
+         This is a general conntrack match module, a superset of the state match.
+
+         It allows matching on additional conntrack information, which is
+         useful in complex configurations, such as NAT gateways with multiple
+         internet links or tunnels.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_DCCP
+       tristate  '"DCCP" protocol match support'
+       depends on NETFILTER_XTABLES
+       help
+         With this option enabled, you will be able to use the iptables
+         `dccp' match in order to match on DCCP source/destination ports
+         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'.
+
+config NETFILTER_XT_MATCH_HELPER
+       tristate '"helper" match support'
+       depends on NETFILTER_XTABLES
+       depends on IP_NF_CONNTRACK || NF_CONNTRACK
+       help
+         Helper matching allows you to match packets in dynamic connections
+         tracked by a conntrack-helper, ie. ip_conntrack_ftp
+
+         To compile it as a module, choose M here.  If unsure, say Y.
+
+config NETFILTER_XT_MATCH_LENGTH
+       tristate '"length" match support'
+       depends on NETFILTER_XTABLES
+       help
+         This option allows you to match the length of a packet against a
+         specific value or range of values.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_LIMIT
+       tristate '"limit" match support'
+       depends on NETFILTER_XTABLES
+       help
+         limit matching allows you to control the rate at which a rule can be
+         matched: mainly useful in combination with the LOG target ("LOG
+         target support", below) and to avoid some Denial of Service attacks.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_MAC
+       tristate '"mac" address match support'
+       depends on NETFILTER_XTABLES
+       help
+         MAC matching allows you to match packets based on the source
+         Ethernet address of the packet.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_MARK
+       tristate '"mark" match support'
+       depends on NETFILTER_XTABLES
+       help
+         Netfilter mark matching allows you to match packets based on the
+         `nfmark' value in the packet.  This can be set by the MARK target
+         (see below).
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_PHYSDEV
+       tristate '"physdev" match support'
+       depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
+       help
+         Physdev packet matching matches against the physical bridge ports
+         the IP packet arrived on or will leave by.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_PKTTYPE
+       tristate '"pkttype" packet type match support'
+       depends on NETFILTER_XTABLES
+       help
+         Packet type matching allows you to match a packet by
+         its "class", eg. BROADCAST, MULTICAST, ...
+
+         Typical usage:
+         iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_REALM
+       tristate  '"realm" match support'
+       depends on NETFILTER_XTABLES
+       select NET_CLS_ROUTE
+       help
+         This option adds a `realm' match, which allows you to use the realm
+         key from the routing subsystem inside iptables.
+       
+         This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option 
+         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'.
+
+config NETFILTER_XT_MATCH_SCTP
+       tristate  '"sctp" protocol match support'
+       depends on NETFILTER_XTABLES
+       help
+         With this option enabled, you will be able to use the 
+         `sctp' match in order to match on SCTP source/destination ports
+         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'.
+
+config NETFILTER_XT_MATCH_STATE
+       tristate '"state" match support'
+       depends on NETFILTER_XTABLES
+       depends on IP_NF_CONNTRACK || NF_CONNTRACK
+       help
+         Connection state matching allows you to match packets based on their
+         relationship to a tracked connection (ie. previous packets).  This
+         is a powerful tool for packet classification.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_STRING
+       tristate  '"string" match support'
+       depends on NETFILTER_XTABLES
+       select TEXTSEARCH
+       select TEXTSEARCH_KMP
+       select TEXTSEARCH_BM
+       select TEXTSEARCH_FSM
+       help
+         This option adds a `string' match, which allows you to look for
+         pattern matchings in packets.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
+config NETFILTER_XT_MATCH_TCPMSS
+       tristate '"tcpmss" match support'
+       depends on NETFILTER_XTABLES
+       help
+         This option adds a `tcpmss' match, which allows you to examine the
+         MSS value of TCP SYN packets, which control the maximum packet size
+         for that connection.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
index cb2183145c3723f290ef99833c2511d21ae5232d..746172ebc91bbce7bf26deee69c00e498a1321ee 100644 (file)
@@ -1,4 +1,5 @@
 netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
+nf_conntrack-objs      := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
 
 obj-$(CONFIG_NETFILTER) = netfilter.o
 
@@ -6,13 +7,43 @@ obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
 obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
 obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
 
-nf_conntrack-objs      := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
-
+# connection tracking
 obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
-obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
 
 # SCTP protocol connection tracking
 obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
 
 # netlink interface for nf_conntrack
 obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
+
+# connection tracking helpers
+obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
+
+# generic X tables 
+obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
+
+# targets
+obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
+
+# matches
+obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_SCTP) += xt_sctp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_STATE) += xt_state.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
index d5a6eaf4a1defcd39c1343eaff7da7c587a20205..ab0c920f0d30bbf840d731f8c6baddaab7c3f089 100644 (file)
@@ -545,11 +545,11 @@ static int help(struct sk_buff **pskb,
                    different IP address.  Simply don't record it for
                    NAT. */
                if (cmd.l3num == PF_INET) {
-                       DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
+                       DEBUGP("conntrack_ftp: NOT RECORDING: " NIPQUAD_FMT " != " NIPQUAD_FMT "\n",
                               NIPQUAD(cmd.u3.ip),
                               NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
                } else {
-                       DEBUGP("conntrack_ftp: NOT RECORDING: %x:%x:%x:%x:%x:%x:%x:%x != %x:%x:%x:%x:%x:%x:%x:%x\n",
+                       DEBUGP("conntrack_ftp: NOT RECORDING: " NIP6_FMT " != " NIP6_FMT "\n",
                               NIP6(*((struct in6_addr *)cmd.u3.ip6)),
                               NIP6(*((struct in6_addr *)ct->tuplehash[dir]
                                                        .tuple.src.u3.ip6)));
index 3531d142f693fe686923b5c1e3e3b119224644b3..617599aeeead1c94aa7de5bda3fbd226ec5da3ae 100644 (file)
@@ -821,7 +821,7 @@ module_exit(fini);
 
 /* Some modules need us, but don't depend directly on any symbol.
    They should call this. */
-void need_nf_conntrack(void)
+void need_conntrack(void)
 {
 }
 
@@ -841,7 +841,7 @@ EXPORT_SYMBOL(nf_conntrack_protocol_unregister);
 EXPORT_SYMBOL(nf_ct_invert_tuplepr);
 EXPORT_SYMBOL(nf_conntrack_alter_reply);
 EXPORT_SYMBOL(nf_conntrack_destroyed);
-EXPORT_SYMBOL(need_nf_conntrack);
+EXPORT_SYMBOL(need_conntrack);
 EXPORT_SYMBOL(nf_conntrack_helper_register);
 EXPORT_SYMBOL(nf_conntrack_helper_unregister);
 EXPORT_SYMBOL(nf_ct_iterate_cleanup);
index 95fdf04f1d88d239b37bdc26e8aeaeee79b0187f..f6063e8f0050e93778ceac0b809e75f767c8c306 100644 (file)
@@ -212,7 +212,7 @@ int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
 }
 
 /* Process one complete nfnetlink message. */
-static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
+static int nfnetlink_rcv_msg(struct sk_buff *skb,
                                    struct nlmsghdr *nlh, int *errp)
 {
        struct nfnl_callback *nc;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
new file mode 100644 (file)
index 0000000..d7817af
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * x_tables core - Backend for {ip,ip6,arp}_tables
+ *
+ * Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
+ *
+ * Based on existing ip_tables code which is
+ *   Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *   Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.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/config.h>
+#include <linux/kernel.h>
+#include <linux/socket.h>
+#include <linux/net.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_arp.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("[ip,ip6,arp]_tables backend module");
+
+#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
+
+struct xt_af {
+       struct semaphore mutex;
+       struct list_head match;
+       struct list_head target;
+       struct list_head tables;
+};
+
+static struct xt_af *xt;
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+enum {
+       TABLE,
+       TARGET,
+       MATCH,
+};
+
+/* Registration hooks for targets. */
+int
+xt_register_target(int af, struct xt_target *target)
+{
+       int ret;
+
+       ret = down_interruptible(&xt[af].mutex);
+       if (ret != 0)
+               return ret;
+       list_add(&target->list, &xt[af].target);
+       up(&xt[af].mutex);
+       return ret;
+}
+EXPORT_SYMBOL(xt_register_target);
+
+void
+xt_unregister_target(int af, struct xt_target *target)
+{
+       down(&xt[af].mutex);
+       LIST_DELETE(&xt[af].target, target);
+       up(&xt[af].mutex);
+}
+EXPORT_SYMBOL(xt_unregister_target);
+
+int
+xt_register_match(int af, struct xt_match *match)
+{
+       int ret;
+
+       ret = down_interruptible(&xt[af].mutex);
+       if (ret != 0)
+               return ret;
+
+       list_add(&match->list, &xt[af].match);
+       up(&xt[af].mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(xt_register_match);
+
+void
+xt_unregister_match(int af, struct xt_match *match)
+{
+       down(&xt[af].mutex);
+       LIST_DELETE(&xt[af].match, match);
+       up(&xt[af].mutex);
+}
+EXPORT_SYMBOL(xt_unregister_match);
+
+
+/*
+ * These are weird, but module loading must not be done with mutex
+ * held (since they will register), and we have to have a single
+ * function to use try_then_request_module().
+ */
+
+/* Find match, grabs ref.  Returns ERR_PTR() on error. */
+struct xt_match *xt_find_match(int af, const char *name, u8 revision)
+{
+       struct xt_match *m;
+       int err = 0;
+
+       if (down_interruptible(&xt[af].mutex) != 0)
+               return ERR_PTR(-EINTR);
+
+       list_for_each_entry(m, &xt[af].match, list) {
+               if (strcmp(m->name, name) == 0) {
+                       if (m->revision == revision) {
+                               if (try_module_get(m->me)) {
+                                       up(&xt[af].mutex);
+                                       return m;
+                               }
+                       } else
+                               err = -EPROTOTYPE; /* Found something. */
+               }
+       }
+       up(&xt[af].mutex);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(xt_find_match);
+
+/* Find target, grabs ref.  Returns ERR_PTR() on error. */
+struct xt_target *xt_find_target(int af, const char *name, u8 revision)
+{
+       struct xt_target *t;
+       int err = 0;
+
+       if (down_interruptible(&xt[af].mutex) != 0)
+               return ERR_PTR(-EINTR);
+
+       list_for_each_entry(t, &xt[af].target, list) {
+               if (strcmp(t->name, name) == 0) {
+                       if (t->revision == revision) {
+                               if (try_module_get(t->me)) {
+                                       up(&xt[af].mutex);
+                                       return t;
+                               }
+                       } else
+                               err = -EPROTOTYPE; /* Found something. */
+               }
+       }
+       up(&xt[af].mutex);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(xt_find_target);
+
+static const char *xt_prefix[NPROTO] = {
+       [AF_INET]       = "ipt_%s",
+       [AF_INET6]      = "ip6t_%s",
+       [NF_ARP]        = "arpt_%s",
+};
+
+struct xt_target *xt_request_find_target(int af, const char *name, u8 revision)
+{
+       struct xt_target *target;
+
+       target = try_then_request_module(xt_find_target(af, name, revision),
+                                        xt_prefix[af], name);
+       if (IS_ERR(target) || !target)
+               return NULL;
+       return target;
+}
+EXPORT_SYMBOL_GPL(xt_request_find_target);
+
+static int match_revfn(int af, const char *name, u8 revision, int *bestp)
+{
+       struct xt_match *m;
+       int have_rev = 0;
+
+       list_for_each_entry(m, &xt[af].match, list) {
+               if (strcmp(m->name, name) == 0) {
+                       if (m->revision > *bestp)
+                               *bestp = m->revision;
+                       if (m->revision == revision)
+                               have_rev = 1;
+               }
+       }
+       return have_rev;
+}
+
+static int target_revfn(int af, const char *name, u8 revision, int *bestp)
+{
+       struct xt_target *t;
+       int have_rev = 0;
+
+       list_for_each_entry(t, &xt[af].target, list) {
+               if (strcmp(t->name, name) == 0) {
+                       if (t->revision > *bestp)
+                               *bestp = t->revision;
+                       if (t->revision == revision)
+                               have_rev = 1;
+               }
+       }
+       return have_rev;
+}
+
+/* Returns true or false (if no such extension at all) */
+int xt_find_revision(int af, const char *name, u8 revision, int target,
+                    int *err)
+{
+       int have_rev, best = -1;
+
+       if (down_interruptible(&xt[af].mutex) != 0) {
+               *err = -EINTR;
+               return 1;
+       }
+       if (target == 1)
+               have_rev = target_revfn(af, name, revision, &best);
+       else
+               have_rev = match_revfn(af, name, revision, &best);
+       up(&xt[af].mutex);
+
+       /* Nothing at all?  Return 0 to try loading module. */
+       if (best == -1) {
+               *err = -ENOENT;
+               return 0;
+       }
+
+       *err = best;
+       if (!have_rev)
+               *err = -EPROTONOSUPPORT;
+       return 1;
+}
+EXPORT_SYMBOL_GPL(xt_find_revision);
+
+struct xt_table_info *xt_alloc_table_info(unsigned int size)
+{
+       struct xt_table_info *newinfo;
+       int cpu;
+
+       /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
+       if ((SMP_ALIGN(size) >> PAGE_SHIFT) + 2 > num_physpages)
+               return NULL;
+
+       newinfo = kzalloc(sizeof(struct xt_table_info), GFP_KERNEL);
+       if (!newinfo)
+               return NULL;
+
+       newinfo->size = size;
+
+       for_each_cpu(cpu) {
+               if (size <= PAGE_SIZE)
+                       newinfo->entries[cpu] = kmalloc_node(size,
+                                                       GFP_KERNEL,
+                                                       cpu_to_node(cpu));
+               else
+                       newinfo->entries[cpu] = vmalloc_node(size,
+                                                       cpu_to_node(cpu));
+
+               if (newinfo->entries[cpu] == NULL) {
+                       xt_free_table_info(newinfo);
+                       return NULL;
+               }
+       }
+
+       return newinfo;
+}
+EXPORT_SYMBOL(xt_alloc_table_info);
+
+void xt_free_table_info(struct xt_table_info *info)
+{
+       int cpu;
+
+       for_each_cpu(cpu) {
+               if (info->size <= PAGE_SIZE)
+                       kfree(info->entries[cpu]);
+               else
+                       vfree(info->entries[cpu]);
+       }
+       kfree(info);
+}
+EXPORT_SYMBOL(xt_free_table_info);
+
+/* Find table by name, grabs mutex & ref.  Returns ERR_PTR() on error. */
+struct xt_table *xt_find_table_lock(int af, const char *name)
+{
+       struct xt_table *t;
+
+       if (down_interruptible(&xt[af].mutex) != 0)
+               return ERR_PTR(-EINTR);
+
+       list_for_each_entry(t, &xt[af].tables, list)
+               if (strcmp(t->name, name) == 0 && try_module_get(t->me))
+                       return t;
+       up(&xt[af].mutex);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(xt_find_table_lock);
+
+void xt_table_unlock(struct xt_table *table)
+{
+       up(&xt[table->af].mutex);
+}
+EXPORT_SYMBOL_GPL(xt_table_unlock);
+
+
+struct xt_table_info *
+xt_replace_table(struct xt_table *table,
+             unsigned int num_counters,
+             struct xt_table_info *newinfo,
+             int *error)
+{
+       struct xt_table_info *oldinfo, *private;
+
+       /* Do the substitution. */
+       write_lock_bh(&table->lock);
+       private = table->private;
+       /* Check inside lock: is the old number correct? */
+       if (num_counters != private->number) {
+               duprintf("num_counters != table->private->number (%u/%u)\n",
+                        num_counters, private->number);
+               write_unlock_bh(&table->lock);
+               *error = -EAGAIN;
+               return NULL;
+       }
+       oldinfo = private;
+       table->private = newinfo;
+       newinfo->initial_entries = oldinfo->initial_entries;
+       write_unlock_bh(&table->lock);
+
+       return oldinfo;
+}
+EXPORT_SYMBOL_GPL(xt_replace_table);
+
+int xt_register_table(struct xt_table *table,
+                     struct xt_table_info *bootstrap,
+                     struct xt_table_info *newinfo)
+{
+       int ret;
+       struct xt_table_info *private;
+
+       ret = down_interruptible(&xt[table->af].mutex);
+       if (ret != 0)
+               return ret;
+
+       /* Don't autoload: we'd eat our tail... */
+       if (list_named_find(&xt[table->af].tables, table->name)) {
+               ret = -EEXIST;
+               goto unlock;
+       }
+
+       /* Simplifies replace_table code. */
+       table->private = bootstrap;
+       if (!xt_replace_table(table, 0, newinfo, &ret))
+               goto unlock;
+
+       private = table->private;
+       duprintf("table->private->number = %u\n", private->number);
+
+       /* save number of initial entries */
+       private->initial_entries = private->number;
+
+       rwlock_init(&table->lock);
+       list_prepend(&xt[table->af].tables, table);
+
+       ret = 0;
+ unlock:
+       up(&xt[table->af].mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(xt_register_table);
+
+void *xt_unregister_table(struct xt_table *table)
+{
+       struct xt_table_info *private;
+
+       down(&xt[table->af].mutex);
+       private = table->private;
+       LIST_DELETE(&xt[table->af].tables, table);
+       up(&xt[table->af].mutex);
+
+       return private;
+}
+EXPORT_SYMBOL_GPL(xt_unregister_table);
+
+#ifdef CONFIG_PROC_FS
+static char *xt_proto_prefix[NPROTO] = {
+       [AF_INET]       = "ip",
+       [AF_INET6]      = "ip6",
+       [NF_ARP]        = "arp",
+};
+
+static struct list_head *xt_get_idx(struct list_head *list, struct seq_file *seq, loff_t pos)
+{
+       struct list_head *head = list->next;
+
+       if (!head || list_empty(list))
+               return NULL;
+
+       while (pos && (head = head->next)) {
+               if (head == list)
+                       return NULL;
+               pos--;
+       }
+       return pos ? NULL : head;
+}
+
+static struct list_head *type2list(u_int16_t af, u_int16_t type)
+{
+       struct list_head *list;
+
+       switch (type) {
+       case TARGET:
+               list = &xt[af].target;
+               break;
+       case MATCH:
+               list = &xt[af].match;
+               break;
+       case TABLE:
+               list = &xt[af].tables;
+               break;
+       default:
+               list = NULL;
+               break;
+       }
+
+       return list;
+}
+
+static void *xt_tgt_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct proc_dir_entry *pde = (struct proc_dir_entry *) seq->private;
+       u_int16_t af = (unsigned long)pde->data & 0xffff;
+       u_int16_t type = (unsigned long)pde->data >> 16;
+       struct list_head *list;
+
+       if (af >= NPROTO)
+               return NULL;
+
+       list = type2list(af, type);
+       if (!list)
+               return NULL;
+
+       if (down_interruptible(&xt[af].mutex) != 0)
+               return NULL;
+       
+       return xt_get_idx(list, seq, *pos);
+}
+
+static void *xt_tgt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct proc_dir_entry *pde = seq->private;
+       u_int16_t af = (unsigned long)pde->data & 0xffff;
+       u_int16_t type = (unsigned long)pde->data >> 16;
+       struct list_head *list;
+
+       if (af >= NPROTO)
+               return NULL;
+       
+       list = type2list(af, type);
+       if (!list)
+               return NULL;
+
+       (*pos)++;
+       return xt_get_idx(list, seq, *pos);
+}
+
+static void xt_tgt_seq_stop(struct seq_file *seq, void *v)
+{
+       struct proc_dir_entry *pde = seq->private;
+       u_int16_t af = (unsigned long)pde->data & 0xffff;
+
+       up(&xt[af].mutex);
+}
+
+static int xt_name_seq_show(struct seq_file *seq, void *v)
+{
+       char *name = (char *)v + sizeof(struct list_head);
+
+       if (strlen(name))
+               return seq_printf(seq, "%s\n", name);
+       else
+               return 0;
+}
+
+static struct seq_operations xt_tgt_seq_ops = {
+       .start  = xt_tgt_seq_start,
+       .next   = xt_tgt_seq_next,
+       .stop   = xt_tgt_seq_stop,
+       .show   = xt_name_seq_show,
+};
+
+static int xt_tgt_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       ret = seq_open(file, &xt_tgt_seq_ops);
+       if (!ret) {
+               struct seq_file *seq = file->private_data;
+               struct proc_dir_entry *pde = PDE(inode);
+
+               seq->private = pde;
+       }
+
+       return ret;
+}
+
+static struct file_operations xt_file_ops = {
+       .owner   = THIS_MODULE,
+       .open    = xt_tgt_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+
+#define FORMAT_TABLES  "_tables_names"
+#define        FORMAT_MATCHES  "_tables_matches"
+#define FORMAT_TARGETS         "_tables_targets"
+
+#endif /* CONFIG_PROC_FS */
+
+int xt_proto_init(int af)
+{
+#ifdef CONFIG_PROC_FS
+       char buf[XT_FUNCTION_MAXNAMELEN];
+       struct proc_dir_entry *proc;
+#endif
+
+       if (af >= NPROTO)
+               return -EINVAL;
+
+
+#ifdef CONFIG_PROC_FS
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_TABLES, sizeof(buf));
+       proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
+       if (!proc)
+               goto out;
+       proc->data = (void *) ((unsigned long) af | (TABLE << 16));
+
+
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+       proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
+       if (!proc)
+               goto out_remove_tables;
+       proc->data = (void *) ((unsigned long) af | (MATCH << 16));
+
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_TARGETS, sizeof(buf));
+       proc = proc_net_fops_create(buf, 0440, &xt_file_ops);
+       if (!proc)
+               goto out_remove_matches;
+       proc->data = (void *) ((unsigned long) af | (TARGET << 16));
+#endif
+
+       return 0;
+
+#ifdef CONFIG_PROC_FS
+out_remove_matches:
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+       proc_net_remove(buf);
+
+out_remove_tables:
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_TABLES, sizeof(buf));
+       proc_net_remove(buf);
+out:
+       return -1;
+#endif
+}
+EXPORT_SYMBOL_GPL(xt_proto_init);
+
+void xt_proto_fini(int af)
+{
+#ifdef CONFIG_PROC_FS
+       char buf[XT_FUNCTION_MAXNAMELEN];
+
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_TABLES, sizeof(buf));
+       proc_net_remove(buf);
+
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_TARGETS, sizeof(buf));
+       proc_net_remove(buf);
+
+       strlcpy(buf, xt_proto_prefix[af], sizeof(buf));
+       strlcat(buf, FORMAT_MATCHES, sizeof(buf));
+       proc_net_remove(buf);
+#endif /*CONFIG_PROC_FS*/
+}
+EXPORT_SYMBOL_GPL(xt_proto_fini);
+
+
+static int __init xt_init(void)
+{
+       int i;
+
+       xt = kmalloc(sizeof(struct xt_af) * NPROTO, GFP_KERNEL);
+       if (!xt)
+               return -ENOMEM;
+
+       for (i = 0; i < NPROTO; i++) {
+               init_MUTEX(&xt[i].mutex);
+               INIT_LIST_HEAD(&xt[i].target);
+               INIT_LIST_HEAD(&xt[i].match);
+               INIT_LIST_HEAD(&xt[i].tables);
+       }
+       return 0;
+}
+
+static void __exit xt_fini(void)
+{
+       kfree(xt);
+}
+
+module_init(xt_init);
+module_exit(xt_fini);
+
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
new file mode 100644 (file)
index 0000000..78ee266
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This is a module which is used for setting the skb->priority field
+ * of an skb for qdisc classification.
+ */
+
+/* (C) 2001-2002 Patrick McHardy <kaber@trash.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/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CLASSIFY.h>
+
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("iptables qdisc classification target module");
+MODULE_ALIAS("ipt_CLASSIFY");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct xt_classify_target_info *clinfo = targinfo;
+
+       if ((*pskb)->priority != clinfo->priority)
+               (*pskb)->priority = clinfo->priority;
+
+       return XT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+           const void *e,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+       if (targinfosize != XT_ALIGN(sizeof(struct xt_classify_target_info))){
+               printk(KERN_ERR "CLASSIFY: invalid size (%u != %Zu).\n",
+                      targinfosize,
+                      XT_ALIGN(sizeof(struct xt_classify_target_info)));
+               return 0;
+       }
+       
+       if (hook_mask & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+                         (1 << NF_IP_POST_ROUTING))) {
+               printk(KERN_ERR "CLASSIFY: only valid in LOCAL_OUT, FORWARD "
+                               "and POST_ROUTING.\n");
+               return 0;
+       }
+
+       if (strcmp(tablename, "mangle") != 0) {
+               printk(KERN_ERR "CLASSIFY: can only be called from "
+                               "\"mangle\" table, not \"%s\".\n",
+                               tablename);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_target classify_reg = { 
+       .name           = "CLASSIFY", 
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_target classify6_reg = { 
+       .name           = "CLASSIFY", 
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = xt_register_target(AF_INET, &classify_reg);
+       if (ret)
+               return ret;
+
+       ret = xt_register_target(AF_INET6, &classify6_reg);
+       if (ret)
+               xt_unregister_target(AF_INET, &classify_reg);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_target(AF_INET, &classify_reg);
+       xt_unregister_target(AF_INET6, &classify6_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
new file mode 100644 (file)
index 0000000..22506e3
--- /dev/null
@@ -0,0 +1,141 @@
+/* This kernel module is used to modify the connection mark values, or
+ * to optionally restore the skb nfmark from the connection mark
+ *
+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.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/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
+MODULE_DESCRIPTION("IP tables CONNMARK matching module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_CONNMARK");
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_CONNMARK.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct xt_connmark_target_info *markinfo = targinfo;
+       u_int32_t diff;
+       u_int32_t nfmark;
+       u_int32_t newmark;
+       u_int32_t ctinfo;
+       u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
+
+       if (ctmark) {
+           switch(markinfo->mode) {
+           case XT_CONNMARK_SET:
+               newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
+               if (newmark != *ctmark)
+                   *ctmark = newmark;
+               break;
+           case XT_CONNMARK_SAVE:
+               newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
+               if (*ctmark != newmark)
+                   *ctmark = newmark;
+               break;
+           case XT_CONNMARK_RESTORE:
+               nfmark = (*pskb)->nfmark;
+               diff = (*ctmark ^ nfmark) & markinfo->mask;
+               if (diff != 0)
+                   (*pskb)->nfmark = nfmark ^ diff;
+               break;
+           }
+       }
+
+       return XT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+          const void *entry,
+          void *targinfo,
+          unsigned int targinfosize,
+          unsigned int hook_mask)
+{
+       struct xt_connmark_target_info *matchinfo = targinfo;
+       if (targinfosize != XT_ALIGN(sizeof(struct xt_connmark_target_info))) {
+               printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      XT_ALIGN(sizeof(struct xt_connmark_target_info)));
+               return 0;
+       }
+
+       if (matchinfo->mode == XT_CONNMARK_RESTORE) {
+           if (strcmp(tablename, "mangle") != 0) {
+                   printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+                   return 0;
+           }
+       }
+
+       if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
+               printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_target connmark_reg = {
+       .name = "CONNMARK",
+       .target = &target,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+static struct xt_target connmark6_reg = {
+       .name = "CONNMARK",
+       .target = &target,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       need_conntrack();
+
+       ret = xt_register_target(AF_INET, &connmark_reg);
+       if (ret)
+               return ret;
+
+       ret = xt_register_target(AF_INET6, &connmark6_reg);
+       if (ret)
+               xt_unregister_target(AF_INET, &connmark_reg);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_target(AF_INET, &connmark_reg);
+       xt_unregister_target(AF_INET6, &connmark6_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
new file mode 100644 (file)
index 0000000..0c11ee9
--- /dev/null
@@ -0,0 +1,191 @@
+/* This is a module which is used for setting the NFMARK field of an skb. */
+
+/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
+ *
+ * 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/skbuff.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_MARK.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("ip[6]tables MARK modification module");
+MODULE_ALIAS("ipt_MARK");
+MODULE_ALIAS("ip6t_MARK");
+
+static unsigned int
+target_v0(struct sk_buff **pskb,
+         const struct net_device *in,
+         const struct net_device *out,
+         unsigned int hooknum,
+         const void *targinfo,
+         void *userinfo)
+{
+       const struct xt_mark_target_info *markinfo = targinfo;
+
+       if((*pskb)->nfmark != markinfo->mark)
+               (*pskb)->nfmark = markinfo->mark;
+
+       return XT_CONTINUE;
+}
+
+static unsigned int
+target_v1(struct sk_buff **pskb,
+         const struct net_device *in,
+         const struct net_device *out,
+         unsigned int hooknum,
+         const void *targinfo,
+         void *userinfo)
+{
+       const struct xt_mark_target_info_v1 *markinfo = targinfo;
+       int mark = 0;
+
+       switch (markinfo->mode) {
+       case XT_MARK_SET:
+               mark = markinfo->mark;
+               break;
+               
+       case XT_MARK_AND:
+               mark = (*pskb)->nfmark & markinfo->mark;
+               break;
+               
+       case XT_MARK_OR:
+               mark = (*pskb)->nfmark | markinfo->mark;
+               break;
+       }
+
+       if((*pskb)->nfmark != mark)
+               (*pskb)->nfmark = mark;
+
+       return XT_CONTINUE;
+}
+
+
+static int
+checkentry_v0(const char *tablename,
+             const void *entry,
+             void *targinfo,
+             unsigned int targinfosize,
+             unsigned int hook_mask)
+{
+       struct xt_mark_target_info *markinfo = targinfo;
+
+       if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info))) {
+               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      XT_ALIGN(sizeof(struct xt_mark_target_info)));
+               return 0;
+       }
+
+       if (strcmp(tablename, "mangle") != 0) {
+               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+               return 0;
+       }
+
+       if (markinfo->mark > 0xffffffff) {
+               printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+checkentry_v1(const char *tablename,
+             const void *entry,
+             void *targinfo,
+             unsigned int targinfosize,
+             unsigned int hook_mask)
+{
+       struct xt_mark_target_info_v1 *markinfo = targinfo;
+
+       if (targinfosize != XT_ALIGN(sizeof(struct xt_mark_target_info_v1))){
+               printk(KERN_WARNING "MARK: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      XT_ALIGN(sizeof(struct xt_mark_target_info_v1)));
+               return 0;
+       }
+
+       if (strcmp(tablename, "mangle") != 0) {
+               printk(KERN_WARNING "MARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
+               return 0;
+       }
+
+       if (markinfo->mode != XT_MARK_SET
+           && markinfo->mode != XT_MARK_AND
+           && markinfo->mode != XT_MARK_OR) {
+               printk(KERN_WARNING "MARK: unknown mode %u\n",
+                      markinfo->mode);
+               return 0;
+       }
+
+       if (markinfo->mark > 0xffffffff) {
+               printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_target ipt_mark_reg_v0 = {
+       .name           = "MARK",
+       .target         = target_v0,
+       .checkentry     = checkentry_v0,
+       .me             = THIS_MODULE,
+       .revision       = 0,
+};
+
+static struct xt_target ipt_mark_reg_v1 = {
+       .name           = "MARK",
+       .target         = target_v1,
+       .checkentry     = checkentry_v1,
+       .me             = THIS_MODULE,
+       .revision       = 1,
+};
+
+static struct xt_target ip6t_mark_reg_v0 = {
+       .name           = "MARK",
+       .target         = target_v0,
+       .checkentry     = checkentry_v0,
+       .me             = THIS_MODULE,
+       .revision       = 0,
+};
+
+static int __init init(void)
+{
+       int err;
+
+       err = xt_register_target(AF_INET, &ipt_mark_reg_v0);
+       if (err)
+               return err;
+
+       err = xt_register_target(AF_INET, &ipt_mark_reg_v1);
+       if (err)
+               xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
+
+       err = xt_register_target(AF_INET6, &ip6t_mark_reg_v0);
+       if (err) {
+               xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
+               xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
+       }
+
+       return err;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_target(AF_INET, &ipt_mark_reg_v0);
+       xt_unregister_target(AF_INET, &ipt_mark_reg_v1);
+       xt_unregister_target(AF_INET6, &ip6t_mark_reg_v0);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
new file mode 100644 (file)
index 0000000..8b76b6f
--- /dev/null
@@ -0,0 +1,107 @@
+/* iptables module for using new netfilter netlink queue
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_NFQUEUE.h>
+
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("[ip,ip6,arp]_tables NFQUEUE target");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_NFQUEUE");
+MODULE_ALIAS("ip6t_NFQUEUE");
+MODULE_ALIAS("arpt_NFQUEUE");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       const struct xt_NFQ_info *tinfo = targinfo;
+
+       return NF_QUEUE_NR(tinfo->queuenum);
+}
+
+static int
+checkentry(const char *tablename,
+          const void *entry,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+       if (targinfosize != XT_ALIGN(sizeof(struct xt_NFQ_info))) {
+               printk(KERN_WARNING "NFQUEUE: targinfosize %u != %Zu\n",
+                      targinfosize,
+                      XT_ALIGN(sizeof(struct xt_NFQ_info)));
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_target ipt_NFQ_reg = {
+       .name           = "NFQUEUE",
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_target ip6t_NFQ_reg = {
+       .name           = "NFQUEUE",
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_target arpt_NFQ_reg = {
+       .name           = "NFQUEUE",
+       .target         = target,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_target(AF_INET, &ipt_NFQ_reg);
+       if (ret)
+               return ret;
+       ret = xt_register_target(AF_INET6, &ip6t_NFQ_reg);
+       if (ret)
+               goto out_ip;
+       ret = xt_register_target(NF_ARP, &arpt_NFQ_reg);
+       if (ret)
+               goto out_ip6;
+
+       return ret;
+out_ip6:
+       xt_unregister_target(AF_INET6, &ip6t_NFQ_reg);
+out_ip:
+       xt_unregister_target(AF_INET, &ipt_NFQ_reg);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_target(NF_ARP, &arpt_NFQ_reg);
+       xt_unregister_target(AF_INET6, &ip6t_NFQ_reg);
+       xt_unregister_target(AF_INET, &ipt_NFQ_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
new file mode 100644 (file)
index 0000000..24d477a
--- /dev/null
@@ -0,0 +1,92 @@
+/* This is a module which is used for setting up fake conntracks
+ * on packets so that they are not seen by the conntrack/NAT code.
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_NOTRACK");
+
+static unsigned int
+target(struct sk_buff **pskb,
+       const struct net_device *in,
+       const struct net_device *out,
+       unsigned int hooknum,
+       const void *targinfo,
+       void *userinfo)
+{
+       /* Previously seen (loopback)? Ignore. */
+       if ((*pskb)->nfct != NULL)
+               return XT_CONTINUE;
+
+       /* Attach fake conntrack entry. 
+          If there is a real ct entry correspondig to this packet, 
+          it'll hang aroun till timing out. We don't deal with it
+          for performance reasons. JK */
+       nf_ct_untrack(*pskb);
+       (*pskb)->nfctinfo = IP_CT_NEW;
+       nf_conntrack_get((*pskb)->nfct);
+
+       return XT_CONTINUE;
+}
+
+static int
+checkentry(const char *tablename,
+          const void *entry,
+           void *targinfo,
+           unsigned int targinfosize,
+           unsigned int hook_mask)
+{
+       if (targinfosize != 0) {
+               printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
+                      targinfosize);
+               return 0;
+       }
+
+       if (strcmp(tablename, "raw") != 0) {
+               printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_target notrack_reg = { 
+       .name = "NOTRACK", 
+       .target = target, 
+       .checkentry = checkentry,
+       .me = THIS_MODULE,
+};
+static struct xt_target notrack6_reg = { 
+       .name = "NOTRACK", 
+       .target = target, 
+       .checkentry = checkentry,
+       .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = xt_register_target(AF_INET, &notrack_reg);
+       if (ret)
+               return ret;
+
+       ret = xt_register_target(AF_INET6, &notrack6_reg);
+       if (ret)
+               xt_unregister_target(AF_INET, &notrack_reg);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_target(AF_INET6, &notrack6_reg);
+       xt_unregister_target(AF_INET, &notrack_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c
new file mode 100644 (file)
index 0000000..4ba6fd6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Implements a dummy match to allow attaching comments to rules
+ *
+ * 2003-05-13 Brad Fisher (brad@info-link.net)
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_comment.h>
+
+MODULE_AUTHOR("Brad Fisher <brad@info-link.net>");
+MODULE_DESCRIPTION("iptables comment match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_comment");
+MODULE_ALIAS("ip6t_comment");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protooff,
+      int *hotdrop)
+{
+       /* We always match */
+       return 1;
+}
+
+static int
+checkentry(const char *tablename,
+           const void *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       /* Check the size */
+       if (matchsize != XT_ALIGN(sizeof(struct xt_comment_info)))
+               return 0;
+       return 1;
+}
+
+static struct xt_match comment_match = {
+       .name           = "comment",
+       .match          = match,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
+};
+
+static struct xt_match comment6_match = {
+       .name           = "comment",
+       .match          = match,
+       .checkentry     = checkentry,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = xt_register_match(AF_INET, &comment_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &comment6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &comment_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &comment_match);
+       xt_unregister_match(AF_INET6, &comment6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
new file mode 100644 (file)
index 0000000..150d2a4
--- /dev/null
@@ -0,0 +1,180 @@
+/* Kernel module to match connection tracking byte counter.
+ * GPL (C) 2002 Martin Devera (devik@cdi.cz).
+ *
+ * 2004-07-20 Harald Welte <laforge@netfilter.org>
+ *     - reimplemented to use per-connection accounting counters
+ *     - add functionality to match number of packets
+ *     - add functionality to match average packet size
+ *     - add support to match directions seperately
+ * 2005-10-16 Harald Welte <laforge@netfilter.org>
+ *     - Port to x_tables
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connbytes.h>
+
+#include <asm/div64.h>
+#include <asm/bitops.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
+MODULE_ALIAS("ipt_connbytes");
+
+/* 64bit divisor, dividend and result. dynamic precision */
+static u_int64_t div64_64(u_int64_t dividend, u_int64_t divisor)
+{
+       u_int32_t d = divisor;
+
+       if (divisor > 0xffffffffULL) {
+               unsigned int shift = fls(divisor >> 32);
+
+               d = divisor >> shift;
+               dividend >>= shift;
+       }
+
+       do_div(dividend, d);
+       return dividend;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_connbytes_info *sinfo = matchinfo;
+       u_int64_t what = 0;     /* initialize to make gcc happy */
+       const struct ip_conntrack_counter *counters;
+
+       if (!(counters = nf_ct_get_counters(skb)))
+               return 0; /* no match */
+
+       switch (sinfo->what) {
+       case XT_CONNBYTES_PKTS:
+               switch (sinfo->direction) {
+               case XT_CONNBYTES_DIR_ORIGINAL:
+                       what = counters[IP_CT_DIR_ORIGINAL].packets;
+                       break;
+               case XT_CONNBYTES_DIR_REPLY:
+                       what = counters[IP_CT_DIR_REPLY].packets;
+                       break;
+               case XT_CONNBYTES_DIR_BOTH:
+                       what = counters[IP_CT_DIR_ORIGINAL].packets;
+                       what += counters[IP_CT_DIR_REPLY].packets;
+                       break;
+               }
+               break;
+       case XT_CONNBYTES_BYTES:
+               switch (sinfo->direction) {
+               case XT_CONNBYTES_DIR_ORIGINAL:
+                       what = counters[IP_CT_DIR_ORIGINAL].bytes;
+                       break;
+               case XT_CONNBYTES_DIR_REPLY:
+                       what = counters[IP_CT_DIR_REPLY].bytes;
+                       break;
+               case XT_CONNBYTES_DIR_BOTH:
+                       what = counters[IP_CT_DIR_ORIGINAL].bytes;
+                       what += counters[IP_CT_DIR_REPLY].bytes;
+                       break;
+               }
+               break;
+       case XT_CONNBYTES_AVGPKT:
+               switch (sinfo->direction) {
+               case XT_CONNBYTES_DIR_ORIGINAL:
+                       what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
+                                       counters[IP_CT_DIR_ORIGINAL].packets);
+                       break;
+               case XT_CONNBYTES_DIR_REPLY:
+                       what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
+                                       counters[IP_CT_DIR_REPLY].packets);
+                       break;
+               case XT_CONNBYTES_DIR_BOTH:
+                       {
+                               u_int64_t bytes;
+                               u_int64_t pkts;
+                               bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
+                                       counters[IP_CT_DIR_REPLY].bytes;
+                               pkts = counters[IP_CT_DIR_ORIGINAL].packets+
+                                       counters[IP_CT_DIR_REPLY].packets;
+
+                               /* FIXME_THEORETICAL: what to do if sum
+                                * overflows ? */
+
+                               what = div64_64(bytes, pkts);
+                       }
+                       break;
+               }
+               break;
+       }
+
+       if (sinfo->count.to)
+               return (what <= sinfo->count.to && what >= sinfo->count.from);
+       else
+               return (what >= sinfo->count.from);
+}
+
+static int check(const char *tablename,
+                const void *ip,
+                void *matchinfo,
+                unsigned int matchsize,
+                unsigned int hook_mask)
+{
+       const struct xt_connbytes_info *sinfo = matchinfo;
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_connbytes_info)))
+               return 0;
+
+       if (sinfo->what != XT_CONNBYTES_PKTS &&
+           sinfo->what != XT_CONNBYTES_BYTES &&
+           sinfo->what != XT_CONNBYTES_AVGPKT)
+               return 0;
+
+       if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
+           sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
+           sinfo->direction != XT_CONNBYTES_DIR_BOTH)
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match connbytes_match = {
+       .name           = "connbytes",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE
+};
+static struct xt_match connbytes6_match = {
+       .name           = "connbytes",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &connbytes_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &connbytes6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &connbytes_match);
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &connbytes_match);
+       xt_unregister_match(AF_INET6, &connbytes6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
new file mode 100644 (file)
index 0000000..d06e925
--- /dev/null
@@ -0,0 +1,109 @@
+/* This kernel module matches connection mark values set by the
+ * CONNMARK target
+ *
+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.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/skbuff.h>
+
+MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
+MODULE_DESCRIPTION("IP tables connmark match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_connmark");
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connmark.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_connmark_info *info = matchinfo;
+       u_int32_t ctinfo;
+       const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
+       if (!ctmark)
+               return 0;
+
+       return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+          const void *ip,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       struct xt_connmark_info *cm = 
+                               (struct xt_connmark_info *)matchinfo;
+       if (matchsize != XT_ALIGN(sizeof(struct xt_connmark_info)))
+               return 0;
+
+       if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
+               printk(KERN_WARNING "connmark: only support 32bit mark\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_match connmark_match = {
+       .name = "connmark",
+       .match = &match,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+static struct xt_match connmark6_match = {
+       .name = "connmark",
+       .match = &match,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+
+
+static int __init init(void)
+{
+       int ret;
+
+       need_conntrack();
+
+       ret = xt_register_match(AF_INET, &connmark_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &connmark6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &connmark_match);
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET6, &connmark6_match);
+       xt_unregister_match(AF_INET, &connmark_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
new file mode 100644 (file)
index 0000000..ffdebc9
--- /dev/null
@@ -0,0 +1,238 @@
+/* Kernel module to match connection tracking information.
+ * Superset of Rusty's minimalistic state match.
+ *
+ * (C) 2001  Marc Boucher (marc@mbsi.ca).
+ *
+ * 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/skbuff.h>
+
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#else
+#include <net/netfilter/nf_conntrack.h>
+#endif
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_conntrack.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("iptables connection tracking match module");
+MODULE_ALIAS("ipt_conntrack");
+
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_conntrack_info *sinfo = matchinfo;
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       unsigned int statebit;
+
+       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+
+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+       if (ct == &ip_conntrack_untracked)
+               statebit = XT_CONNTRACK_STATE_UNTRACKED;
+       else if (ct)
+               statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
+       else
+               statebit = XT_CONNTRACK_STATE_INVALID;
+       if(sinfo->flags & XT_CONNTRACK_STATE) {
+               if (ct) {
+                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
+                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
+                               statebit |= XT_CONNTRACK_STATE_SNAT;
+
+                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
+                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
+                               statebit |= XT_CONNTRACK_STATE_DNAT;
+               }
+
+               if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_PROTO) {
+               if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_STATUS) {
+               if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
+               unsigned long expires;
+
+               if(!ct)
+                       return 0;
+
+               expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
+
+               if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
+                       return 0;
+       }
+
+       return 1;
+}
+
+#else /* CONFIG_IP_NF_CONNTRACK */
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_conntrack_info *sinfo = matchinfo;
+       struct nf_conn *ct;
+       enum ip_conntrack_info ctinfo;
+       unsigned int statebit;
+
+       ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
+
+#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
+
+       if (ct == &nf_conntrack_untracked)
+               statebit = XT_CONNTRACK_STATE_UNTRACKED;
+       else if (ct)
+               statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
+       else
+               statebit = XT_CONNTRACK_STATE_INVALID;
+       if(sinfo->flags & XT_CONNTRACK_STATE) {
+               if (ct) {
+                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
+                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
+                               statebit |= XT_CONNTRACK_STATE_SNAT;
+
+                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
+                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
+                               statebit |= XT_CONNTRACK_STATE_DNAT;
+               }
+
+               if (FWINV((statebit & sinfo->statemask) == 0, XT_CONNTRACK_STATE))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_PROTO) {
+               if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_ORIGSRC) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, XT_CONNTRACK_ORIGSRC))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, XT_CONNTRACK_ORIGDST))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, XT_CONNTRACK_REPLSRC))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_REPLDST) {
+               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, XT_CONNTRACK_REPLDST))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_STATUS) {
+               if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, XT_CONNTRACK_STATUS))
+                       return 0;
+       }
+
+       if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
+               unsigned long expires;
+
+               if(!ct)
+                       return 0;
+
+               expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
+
+               if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), XT_CONNTRACK_EXPIRES))
+                       return 0;
+       }
+
+       return 1;
+}
+
+#endif /* CONFIG_NF_IP_CONNTRACK */
+
+static int check(const char *tablename,
+                const void *ip,
+                void *matchinfo,
+                unsigned int matchsize,
+                unsigned int hook_mask)
+{
+       if (matchsize != XT_ALIGN(sizeof(struct xt_conntrack_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match conntrack_match = {
+       .name           = "conntrack",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       need_conntrack();
+       ret = xt_register_match(AF_INET, &conntrack_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &conntrack_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
new file mode 100644 (file)
index 0000000..779f42f
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * iptables module for DCCP protocol header matching
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+#include <linux/spinlock.h>
+#include <net/ip.h>
+#include <linux/dccp.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_dccp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_DESCRIPTION("Match for DCCP protocol packets");
+MODULE_ALIAS("ipt_dccp");
+
+#define DCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
+                                 || (!!((invflag) & (option)) ^ (cond)))
+
+static unsigned char *dccp_optbuf;
+static DEFINE_SPINLOCK(dccp_buflock);
+
+static inline int
+dccp_find_option(u_int8_t option,
+                const struct sk_buff *skb,
+                unsigned int protoff,
+                const struct dccp_hdr *dh,
+                int *hotdrop)
+{
+       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+       unsigned char *op;
+       unsigned int optoff = __dccp_hdr_len(dh);
+       unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
+       unsigned int i;
+
+       if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
+               *hotdrop = 1;
+               return 0;
+       }
+
+       if (!optlen)
+               return 0;
+
+       spin_lock_bh(&dccp_buflock);
+       op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
+       if (op == NULL) {
+               /* If we don't have the whole header, drop packet. */
+               spin_unlock_bh(&dccp_buflock);
+               *hotdrop = 1;
+               return 0;
+       }
+
+       for (i = 0; i < optlen; ) {
+               if (op[i] == option) {
+                       spin_unlock_bh(&dccp_buflock);
+                       return 1;
+               }
+
+               if (op[i] < 2) 
+                       i++;
+               else 
+                       i += op[i+1]?:1;
+       }
+
+       spin_unlock_bh(&dccp_buflock);
+       return 0;
+}
+
+
+static inline int
+match_types(const struct dccp_hdr *dh, u_int16_t typemask)
+{
+       return (typemask & (1 << dh->dccph_type));
+}
+
+static inline int
+match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
+            const struct dccp_hdr *dh, int *hotdrop)
+{
+       return dccp_find_option(option, skb, protoff, dh, hotdrop);
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_dccp_info *info = 
+                               (const struct xt_dccp_info *)matchinfo;
+       struct dccp_hdr _dh, *dh;
+
+       if (offset)
+               return 0;
+       
+       dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh);
+       if (dh == NULL) {
+               *hotdrop = 1;
+               return 0;
+               }
+
+       return  DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0]) 
+                       && (ntohs(dh->dccph_sport) <= info->spts[1])), 
+                       XT_DCCP_SRC_PORTS, info->flags, info->invflags)
+               && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0]) 
+                       && (ntohs(dh->dccph_dport) <= info->dpts[1])), 
+                       XT_DCCP_DEST_PORTS, info->flags, info->invflags)
+               && DCCHECK(match_types(dh, info->typemask),
+                          XT_DCCP_TYPE, info->flags, info->invflags)
+               && DCCHECK(match_option(info->option, skb, protoff, dh,
+                                       hotdrop),
+                          XT_DCCP_OPTION, info->flags, info->invflags);
+}
+
+static int
+checkentry(const char *tablename,
+          const void *inf,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       const struct ipt_ip *ip = inf;
+       const struct xt_dccp_info *info;
+
+       info = (const struct xt_dccp_info *)matchinfo;
+
+       return ip->proto == IPPROTO_DCCP
+               && !(ip->invflags & XT_INV_PROTO)
+               && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
+               && !(info->flags & ~XT_DCCP_VALID_FLAGS)
+               && !(info->invflags & ~XT_DCCP_VALID_FLAGS)
+               && !(info->invflags & ~info->flags);
+}
+
+static int
+checkentry6(const char *tablename,
+          const void *inf,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_ip6 *ip = inf;
+       const struct xt_dccp_info *info;
+
+       info = (const struct xt_dccp_info *)matchinfo;
+
+       return ip->proto == IPPROTO_DCCP
+               && !(ip->invflags & XT_INV_PROTO)
+               && matchsize == XT_ALIGN(sizeof(struct xt_dccp_info))
+               && !(info->flags & ~XT_DCCP_VALID_FLAGS)
+               && !(info->invflags & ~XT_DCCP_VALID_FLAGS)
+               && !(info->invflags & ~info->flags);
+}
+
+
+static struct xt_match dccp_match = 
+{ 
+       .name           = "dccp",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match dccp6_match = 
+{ 
+       .name           = "dccp",
+       .match          = &match,
+       .checkentry     = &checkentry6,
+       .me             = THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+       int ret;
+
+       /* doff is 8 bits, so the maximum option size is (4*256).  Don't put
+        * this in BSS since DaveM is worried about locked TLB's for kernel
+        * BSS. */
+       dccp_optbuf = kmalloc(256 * 4, GFP_KERNEL);
+       if (!dccp_optbuf)
+               return -ENOMEM;
+       ret = xt_register_match(AF_INET, &dccp_match);
+       if (ret)
+               goto out_kfree;
+       ret = xt_register_match(AF_INET6, &dccp6_match);
+       if (ret)
+               goto out_unreg;
+
+       return ret;
+
+out_unreg:
+       xt_unregister_match(AF_INET, &dccp_match);
+out_kfree:
+       kfree(dccp_optbuf);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET6, &dccp6_match);
+       xt_unregister_match(AF_INET, &dccp_match);
+       kfree(dccp_optbuf);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
new file mode 100644 (file)
index 0000000..38b6715
--- /dev/null
@@ -0,0 +1,188 @@
+/* iptables module to match on related connections */
+/*
+ * (C) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
+ *
+ * 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.
+ *
+ *   19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *              - Port to newnat infrastructure
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#else
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_helper.h>
+#endif
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_helper.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
+MODULE_DESCRIPTION("iptables helper match module");
+MODULE_ALIAS("ipt_helper");
+MODULE_ALIAS("ip6t_helper");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_helper_info *info = matchinfo;
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       int ret = info->invert;
+       
+       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
+       if (!ct) {
+               DEBUGP("xt_helper: Eek! invalid conntrack?\n");
+               return ret;
+       }
+
+       if (!ct->master) {
+               DEBUGP("xt_helper: conntrack %p has no master\n", ct);
+               return ret;
+       }
+
+       read_lock_bh(&ip_conntrack_lock);
+       if (!ct->master->helper) {
+               DEBUGP("xt_helper: master ct %p has no helper\n", 
+                       exp->expectant);
+               goto out_unlock;
+       }
+
+       DEBUGP("master's name = %s , info->name = %s\n", 
+               ct->master->helper->name, info->name);
+
+       if (info->name[0] == '\0')
+               ret ^= 1;
+       else
+               ret ^= !strncmp(ct->master->helper->name, info->name, 
+                               strlen(ct->master->helper->name));
+out_unlock:
+       read_unlock_bh(&ip_conntrack_lock);
+       return ret;
+}
+
+#else /* CONFIG_IP_NF_CONNTRACK */
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_helper_info *info = matchinfo;
+       struct nf_conn *ct;
+       enum ip_conntrack_info ctinfo;
+       int ret = info->invert;
+       
+       ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
+       if (!ct) {
+               DEBUGP("xt_helper: Eek! invalid conntrack?\n");
+               return ret;
+       }
+
+       if (!ct->master) {
+               DEBUGP("xt_helper: conntrack %p has no master\n", ct);
+               return ret;
+       }
+
+       read_lock_bh(&nf_conntrack_lock);
+       if (!ct->master->helper) {
+               DEBUGP("xt_helper: master ct %p has no helper\n", 
+                       exp->expectant);
+               goto out_unlock;
+       }
+
+       DEBUGP("master's name = %s , info->name = %s\n", 
+               ct->master->helper->name, info->name);
+
+       if (info->name[0] == '\0')
+               ret ^= 1;
+       else
+               ret ^= !strncmp(ct->master->helper->name, info->name, 
+                               strlen(ct->master->helper->name));
+out_unlock:
+       read_unlock_bh(&nf_conntrack_lock);
+       return ret;
+}
+#endif
+
+static int check(const char *tablename,
+                const void *inf,
+                void *matchinfo,
+                unsigned int matchsize,
+                unsigned int hook_mask)
+{
+       struct xt_helper_info *info = matchinfo;
+
+       info->name[29] = '\0';
+
+       /* verify size */
+       if (matchsize != XT_ALIGN(sizeof(struct xt_helper_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match helper_match = {
+       .name           = "helper",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE,
+};
+static struct xt_match helper6_match = {
+       .name           = "helper",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       need_conntrack();
+
+       ret = xt_register_match(AF_INET, &helper_match);
+       if (ret < 0)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &helper6_match);
+       if (ret < 0)
+               xt_unregister_match(AF_INET, &helper_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &helper_match);
+       xt_unregister_match(AF_INET6, &helper6_match);
+}
+
+module_init(init);
+module_exit(fini);
+
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
new file mode 100644 (file)
index 0000000..39c8fae
--- /dev/null
@@ -0,0 +1,99 @@
+/* Kernel module to match packet length. */
+/* (C) 1999-2001 James Morris <jmorros@intercode.com.au>
+ *
+ * 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/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ip.h>
+
+#include <linux/netfilter/xt_length.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
+MODULE_DESCRIPTION("IP tables packet length matching module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_length");
+MODULE_ALIAS("ip6t_length");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_length_info *info = matchinfo;
+       u_int16_t pktlen = ntohs(skb->nh.iph->tot_len);
+       
+       return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+match6(const struct sk_buff *skb,
+       const struct net_device *in,
+       const struct net_device *out,
+       const void *matchinfo,
+       int offset,
+       unsigned int protoff,
+       int *hotdrop)
+{
+       const struct xt_length_info *info = matchinfo;
+       u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
+       
+       return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+           const void *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       if (matchsize != XT_ALIGN(sizeof(struct xt_length_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match length_match = {
+       .name           = "length",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match length6_match = {
+       .name           = "length",
+       .match          = &match6,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &length_match);
+       if (ret)
+               return ret;
+       ret = xt_register_match(AF_INET6, &length6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &length_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &length_match);
+       xt_unregister_match(AF_INET6, &length6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
new file mode 100644 (file)
index 0000000..15e4050
--- /dev/null
@@ -0,0 +1,175 @@
+/* Kernel module to control the rate
+ *
+ * 2 September 1999: Changed from the target RATE to the match
+ *                   `limit', removed logging.  Did I mention that
+ *                   Alexey is a fucking genius?
+ *                   Rusty Russell (rusty@rustcorp.com.au).  */
+
+/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
+ * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
+ *
+ * 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/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_limit.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
+MODULE_DESCRIPTION("iptables rate limit match");
+MODULE_ALIAS("ipt_limit");
+MODULE_ALIAS("ip6t_limit");
+
+/* The algorithm used is the Simple Token Bucket Filter (TBF)
+ * see net/sched/sch_tbf.c in the linux source tree
+ */
+
+static DEFINE_SPINLOCK(limit_lock);
+
+/* Rusty: This is my (non-mathematically-inclined) understanding of
+   this algorithm.  The `average rate' in jiffies becomes your initial
+   amount of credit `credit' and the most credit you can ever have
+   `credit_cap'.  The `peak rate' becomes the cost of passing the
+   test, `cost'.
+
+   `prev' tracks the last packet hit: you gain one credit per jiffy.
+   If you get credit balance more than this, the extra credit is
+   discarded.  Every time the match passes, you lose `cost' credits;
+   if you don't have that many, the test fails.
+
+   See Alexey's formal explanation in net/sched/sch_tbf.c.
+
+   To get the maxmum range, we multiply by this factor (ie. you get N
+   credits per jiffy).  We want to allow a rate as low as 1 per day
+   (slowest userspace tool allows), which means
+   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */
+#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
+
+/* Repeated shift and or gives us all 1s, final shift and add 1 gives
+ * us the power of 2 below the theoretical max, so GCC simply does a
+ * shift. */
+#define _POW2_BELOW2(x) ((x)|((x)>>1))
+#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
+#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
+#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
+#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
+#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
+
+#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
+
+static int
+ipt_limit_match(const struct sk_buff *skb,
+               const struct net_device *in,
+               const struct net_device *out,
+               const void *matchinfo,
+               int offset,
+               unsigned int protoff,
+               int *hotdrop)
+{
+       struct xt_rateinfo *r = ((struct xt_rateinfo *)matchinfo)->master;
+       unsigned long now = jiffies;
+
+       spin_lock_bh(&limit_lock);
+       r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
+       if (r->credit > r->credit_cap)
+               r->credit = r->credit_cap;
+
+       if (r->credit >= r->cost) {
+               /* We're not limited. */
+               r->credit -= r->cost;
+               spin_unlock_bh(&limit_lock);
+               return 1;
+       }
+
+               spin_unlock_bh(&limit_lock);
+       return 0;
+}
+
+/* Precision saver. */
+static u_int32_t
+user2credits(u_int32_t user)
+{
+       /* If multiplying would overflow... */
+       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
+               /* Divide first. */
+               return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
+
+       return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
+}
+
+static int
+ipt_limit_checkentry(const char *tablename,
+                    const void *inf,
+                    void *matchinfo,
+                    unsigned int matchsize,
+                    unsigned int hook_mask)
+{
+       struct xt_rateinfo *r = matchinfo;
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_rateinfo)))
+               return 0;
+
+       /* Check for overflow. */
+       if (r->burst == 0
+           || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
+               printk("Overflow in xt_limit, try lower: %u/%u\n",
+                      r->avg, r->burst);
+               return 0;
+       }
+
+       /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
+          128. */
+       r->prev = jiffies;
+       r->credit = user2credits(r->avg * r->burst);     /* Credits full. */
+       r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
+       r->cost = user2credits(r->avg);
+
+       /* For SMP, we only want to use one set of counters. */
+       r->master = r;
+
+       return 1;
+}
+
+static struct xt_match ipt_limit_reg = {
+       .name           = "limit",
+       .match          = ipt_limit_match,
+       .checkentry     = ipt_limit_checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match limit6_reg = {
+       .name           = "limit",
+       .match          = ipt_limit_match,
+       .checkentry     = ipt_limit_checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       
+       ret = xt_register_match(AF_INET, &ipt_limit_reg);
+       if (ret)
+               return ret;
+       
+       ret = xt_register_match(AF_INET6, &limit6_reg);
+       if (ret)
+               xt_unregister_match(AF_INET, &ipt_limit_reg);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &ipt_limit_reg);
+       xt_unregister_match(AF_INET6, &limit6_reg);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
new file mode 100644 (file)
index 0000000..0461dcb
--- /dev/null
@@ -0,0 +1,100 @@
+/* Kernel module to match MAC address parameters. */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.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/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/xt_mac.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+MODULE_DESCRIPTION("iptables mac matching module");
+MODULE_ALIAS("ipt_mac");
+MODULE_ALIAS("ip6t_mac");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+    const struct xt_mac_info *info = matchinfo;
+
+    /* Is mac pointer valid? */
+    return (skb->mac.raw >= skb->head
+           && (skb->mac.raw + ETH_HLEN) <= skb->data
+           /* If so, compare... */
+           && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
+               ^ info->invert));
+}
+
+static int
+ipt_mac_checkentry(const char *tablename,
+                  const void *inf,
+                  void *matchinfo,
+                  unsigned int matchsize,
+                  unsigned int hook_mask)
+{
+       /* FORWARD isn't always valid, but it's nice to be able to do --RR */
+       if (hook_mask
+           & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
+               | (1 << NF_IP_FORWARD))) {
+               printk("xt_mac: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
+               return 0;
+       }
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_mac_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match mac_match = {
+       .name           = "mac",
+       .match          = &match,
+       .checkentry     = &ipt_mac_checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match mac6_match = {
+       .name           = "mac",
+       .match          = &match,
+       .checkentry     = &ipt_mac_checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &mac_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &mac6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &mac_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &mac_match);
+       xt_unregister_match(AF_INET6, &mac6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
new file mode 100644 (file)
index 0000000..2a0ac62
--- /dev/null
@@ -0,0 +1,91 @@
+/* Kernel module to match NFMARK values. */
+
+/* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
+ *
+ * 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/skbuff.h>
+
+#include <linux/netfilter/xt_mark.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("iptables mark matching module");
+MODULE_ALIAS("ipt_mark");
+MODULE_ALIAS("ip6t_mark");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_mark_info *info = matchinfo;
+
+       return ((skb->nfmark & info->mask) == info->mark) ^ info->invert;
+}
+
+static int
+checkentry(const char *tablename,
+           const void *entry,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       struct xt_mark_info *minfo = (struct xt_mark_info *) matchinfo;
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_mark_info)))
+               return 0;
+
+       if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
+               printk(KERN_WARNING "mark: only supports 32bit mark\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_match mark_match = {
+       .name           = "mark",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_match mark6_match = {
+       .name           = "mark",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &mark_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &mark6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &mark_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &mark_match);
+       xt_unregister_match(AF_INET6, &mark6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
new file mode 100644 (file)
index 0000000..19bb57c
--- /dev/null
@@ -0,0 +1,155 @@
+/* Kernel module to match the bridge port in and
+ * out device for IP packets coming into contact with a bridge. */
+
+/* (C) 2001-2003 Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * 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/skbuff.h>
+#include <linux/netfilter/xt_physdev.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_bridge.h>
+#define MATCH   1
+#define NOMATCH 0
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
+MODULE_DESCRIPTION("iptables bridge physical device match module");
+MODULE_ALIAS("ipt_physdev");
+MODULE_ALIAS("ip6t_physdev");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       int i;
+       static const char nulldevname[IFNAMSIZ];
+       const struct xt_physdev_info *info = matchinfo;
+       unsigned int ret;
+       const char *indev, *outdev;
+       struct nf_bridge_info *nf_bridge;
+
+       /* Not a bridged IP packet or no info available yet:
+        * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
+        * the destination device will be a bridge. */
+       if (!(nf_bridge = skb->nf_bridge)) {
+               /* Return MATCH if the invert flags of the used options are on */
+               if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
+                   !(info->invert & XT_PHYSDEV_OP_BRIDGED))
+                       return NOMATCH;
+               if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
+                   !(info->invert & XT_PHYSDEV_OP_ISIN))
+                       return NOMATCH;
+               if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
+                   !(info->invert & XT_PHYSDEV_OP_ISOUT))
+                       return NOMATCH;
+               if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
+                   !(info->invert & XT_PHYSDEV_OP_IN))
+                       return NOMATCH;
+               if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
+                   !(info->invert & XT_PHYSDEV_OP_OUT))
+                       return NOMATCH;
+               return MATCH;
+       }
+
+       /* This only makes sense in the FORWARD and POSTROUTING chains */
+       if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
+           (!!(nf_bridge->mask & BRNF_BRIDGED) ^
+           !(info->invert & XT_PHYSDEV_OP_BRIDGED)))
+               return NOMATCH;
+
+       if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
+           (!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
+           (info->bitmask & XT_PHYSDEV_OP_ISOUT &&
+           (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
+               return NOMATCH;
+
+       if (!(info->bitmask & XT_PHYSDEV_OP_IN))
+               goto match_outdev;
+       indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
+       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+               ret |= (((const unsigned int *)indev)[i]
+                       ^ ((const unsigned int *)info->physindev)[i])
+                       & ((const unsigned int *)info->in_mask)[i];
+       }
+
+       if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN))
+               return NOMATCH;
+
+match_outdev:
+       if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
+               return MATCH;
+       outdev = nf_bridge->physoutdev ?
+                nf_bridge->physoutdev->name : nulldevname;
+       for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+               ret |= (((const unsigned int *)outdev)[i]
+                       ^ ((const unsigned int *)info->physoutdev)[i])
+                       & ((const unsigned int *)info->out_mask)[i];
+       }
+
+       return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT);
+}
+
+static int
+checkentry(const char *tablename,
+                      const void *ip,
+                      void *matchinfo,
+                      unsigned int matchsize,
+                      unsigned int hook_mask)
+{
+       const struct xt_physdev_info *info = matchinfo;
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_physdev_info)))
+               return 0;
+       if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
+           info->bitmask & ~XT_PHYSDEV_OP_MASK)
+               return 0;
+       return 1;
+}
+
+static struct xt_match physdev_match = {
+       .name           = "physdev",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_match physdev6_match = {
+       .name           = "physdev",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = xt_register_match(AF_INET, &physdev_match);
+       if (ret < 0)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &physdev6_match);
+       if (ret < 0)
+               xt_unregister_match(AF_INET, &physdev_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &physdev_match);
+       xt_unregister_match(AF_INET6, &physdev6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
new file mode 100644 (file)
index 0000000..ab1b263
--- /dev/null
@@ -0,0 +1,82 @@
+/* (C) 1999-2001 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+
+#include <linux/netfilter/xt_pkttype.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Ludvig <michal@logix.cz>");
+MODULE_DESCRIPTION("IP tables match to match on linklayer packet type");
+MODULE_ALIAS("ipt_pkttype");
+MODULE_ALIAS("ip6t_pkttype");
+
+static int match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_pkttype_info *info = matchinfo;
+
+       return (skb->pkt_type == info->pkttype) ^ info->invert;
+}
+
+static int checkentry(const char *tablename,
+                  const void *ip,
+                  void *matchinfo,
+                  unsigned int matchsize,
+                  unsigned int hook_mask)
+{
+       if (matchsize != XT_ALIGN(sizeof(struct xt_pkttype_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match pkttype_match = {
+       .name           = "pkttype",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match pkttype6_match = {
+       .name           = "pkttype",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &pkttype_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &pkttype6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &pkttype_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &pkttype_match);
+       xt_unregister_match(AF_INET6, &pkttype6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c
new file mode 100644 (file)
index 0000000..2b7e178
--- /dev/null
@@ -0,0 +1,79 @@
+/* IP tables module for matching the routing realm
+ *
+ * $Id: ipt_realm.c,v 1.3 2004/03/05 13:25:40 laforge Exp $
+ *
+ * (C) 2003 by Sampsa Ranta <sampsa@netsonic.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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <net/route.h>
+
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/xt_realm.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("X_tables realm match");
+MODULE_ALIAS("ipt_realm");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_realm_info *info = matchinfo;
+       struct dst_entry *dst = skb->dst;
+    
+       return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
+}
+
+static int check(const char *tablename,
+                 const void *ip,
+                 void *matchinfo,
+                 unsigned int matchsize,
+                 unsigned int hook_mask)
+{
+       if (hook_mask
+           & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
+               (1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_LOCAL_IN))) {
+               printk("xt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
+                      "LOCAL_IN or FORWARD.\n");
+               return 0;
+       }
+       if (matchsize != XT_ALIGN(sizeof(struct xt_realm_info))) {
+               printk("xt_realm: invalid matchsize.\n");
+               return 0;
+       }
+       return 1;
+}
+
+static struct xt_match realm_match = {
+       .name           = "realm",
+       .match          = match, 
+       .checkentry     = check,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       return xt_register_match(AF_INET, &realm_match);
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &realm_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
new file mode 100644 (file)
index 0000000..10fbfc5
--- /dev/null
@@ -0,0 +1,250 @@
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/sctp.h>
+
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_sctp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kiran Kumar Immidi");
+MODULE_DESCRIPTION("Match for SCTP protocol packets");
+MODULE_ALIAS("ipt_sctp");
+
+#ifdef DEBUG_SCTP
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
+                                             || (!!((invflag) & (option)) ^ (cond)))
+
+static int
+match_flags(const struct xt_sctp_flag_info *flag_info,
+           const int flag_count,
+           u_int8_t chunktype,
+           u_int8_t chunkflags)
+{
+       int i;
+
+       for (i = 0; i < flag_count; i++) {
+               if (flag_info[i].chunktype == chunktype) {
+                       return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
+               }
+       }
+
+       return 1;
+}
+
+static inline int
+match_packet(const struct sk_buff *skb,
+            unsigned int offset,
+            const u_int32_t *chunkmap,
+            int chunk_match_type,
+            const struct xt_sctp_flag_info *flag_info,
+            const int flag_count,
+            int *hotdrop)
+{
+       u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
+       sctp_chunkhdr_t _sch, *sch;
+
+#ifdef DEBUG_SCTP
+       int i = 0;
+#endif
+
+       if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
+               SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
+       }
+
+       do {
+               sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
+               if (sch == NULL) {
+                       duprintf("Dropping invalid SCTP packet.\n");
+                       *hotdrop = 1;
+                       return 0;
+               }
+
+               duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
+                               ++i, offset, sch->type, htons(sch->length), sch->flags);
+
+               offset += (htons(sch->length) + 3) & ~3;
+
+               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
+
+               if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch->type)) {
+                       switch (chunk_match_type) {
+                       case SCTP_CHUNK_MATCH_ANY:
+                               if (match_flags(flag_info, flag_count, 
+                                       sch->type, sch->flags)) {
+                                       return 1;
+                               }
+                               break;
+
+                       case SCTP_CHUNK_MATCH_ALL:
+                               if (match_flags(flag_info, flag_count, 
+                                       sch->type, sch->flags)) {
+                                       SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
+                               }
+                               break;
+
+                       case SCTP_CHUNK_MATCH_ONLY:
+                               if (!match_flags(flag_info, flag_count, 
+                                       sch->type, sch->flags)) {
+                                       return 0;
+                               }
+                               break;
+                       }
+               } else {
+                       switch (chunk_match_type) {
+                       case SCTP_CHUNK_MATCH_ONLY:
+                               return 0;
+                       }
+               }
+       } while (offset < skb->len);
+
+       switch (chunk_match_type) {
+       case SCTP_CHUNK_MATCH_ALL:
+               return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
+       case SCTP_CHUNK_MATCH_ANY:
+               return 0;
+       case SCTP_CHUNK_MATCH_ONLY:
+               return 1;
+       }
+
+       /* This will never be reached, but required to stop compiler whine */
+       return 0;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_sctp_info *info;
+       sctp_sctphdr_t _sh, *sh;
+
+       info = (const struct xt_sctp_info *)matchinfo;
+
+       if (offset) {
+               duprintf("Dropping non-first fragment.. FIXME\n");
+               return 0;
+       }
+       
+       sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh);
+       if (sh == NULL) {
+               duprintf("Dropping evil TCP offset=0 tinygram.\n");
+               *hotdrop = 1;
+               return 0;
+               }
+       duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
+
+       return  SCCHECK(((ntohs(sh->source) >= info->spts[0]) 
+                       && (ntohs(sh->source) <= info->spts[1])), 
+                       XT_SCTP_SRC_PORTS, info->flags, info->invflags)
+               && SCCHECK(((ntohs(sh->dest) >= info->dpts[0]) 
+                       && (ntohs(sh->dest) <= info->dpts[1])), 
+                       XT_SCTP_DEST_PORTS, info->flags, info->invflags)
+               && SCCHECK(match_packet(skb, protoff,
+                                       info->chunkmap, info->chunk_match_type,
+                                       info->flag_info, info->flag_count, 
+                                       hotdrop),
+                          XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
+}
+
+static int
+checkentry(const char *tablename,
+          const void *inf,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       const struct xt_sctp_info *info;
+       const struct ipt_ip *ip = inf;
+
+       info = (const struct xt_sctp_info *)matchinfo;
+
+       return ip->proto == IPPROTO_SCTP
+               && !(ip->invflags & XT_INV_PROTO)
+               && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
+               && !(info->flags & ~XT_SCTP_VALID_FLAGS)
+               && !(info->invflags & ~XT_SCTP_VALID_FLAGS)
+               && !(info->invflags & ~info->flags)
+               && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
+                       (info->chunk_match_type &
+                               (SCTP_CHUNK_MATCH_ALL 
+                               | SCTP_CHUNK_MATCH_ANY
+                               | SCTP_CHUNK_MATCH_ONLY)));
+}
+
+static int
+checkentry6(const char *tablename,
+          const void *inf,
+          void *matchinfo,
+          unsigned int matchsize,
+          unsigned int hook_mask)
+{
+       const struct xt_sctp_info *info;
+       const struct ip6t_ip6 *ip = inf;
+
+       info = (const struct xt_sctp_info *)matchinfo;
+
+       return ip->proto == IPPROTO_SCTP
+               && !(ip->invflags & XT_INV_PROTO)
+               && matchsize == XT_ALIGN(sizeof(struct xt_sctp_info))
+               && !(info->flags & ~XT_SCTP_VALID_FLAGS)
+               && !(info->invflags & ~XT_SCTP_VALID_FLAGS)
+               && !(info->invflags & ~info->flags)
+               && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || 
+                       (info->chunk_match_type &
+                               (SCTP_CHUNK_MATCH_ALL 
+                               | SCTP_CHUNK_MATCH_ANY
+                               | SCTP_CHUNK_MATCH_ONLY)));
+}
+
+
+static struct xt_match sctp_match = 
+{ 
+       .name = "sctp",
+       .match = &match,
+       .checkentry = &checkentry,
+       .me = THIS_MODULE
+};
+static struct xt_match sctp6_match = 
+{ 
+       .name = "sctp",
+       .match = &match,
+       .checkentry = &checkentry6,
+       .me = THIS_MODULE
+};
+
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &sctp_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &sctp6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &sctp_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET6, &sctp6_match);
+       xt_unregister_match(AF_INET, &sctp_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
new file mode 100644 (file)
index 0000000..39ce808
--- /dev/null
@@ -0,0 +1,96 @@
+/* Kernel module to match connection tracking information. */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.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/skbuff.h>
+#include <net/netfilter/nf_conntrack_compat.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_state.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
+MODULE_DESCRIPTION("ip[6]_tables connection tracking state match module");
+MODULE_ALIAS("ipt_state");
+MODULE_ALIAS("ip6t_state");
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_state_info *sinfo = matchinfo;
+       enum ip_conntrack_info ctinfo;
+       unsigned int statebit;
+
+       if (nf_ct_is_untracked(skb))
+               statebit = XT_STATE_UNTRACKED;
+       else if (!nf_ct_get_ctinfo(skb, &ctinfo))
+               statebit = XT_STATE_INVALID;
+       else
+               statebit = XT_STATE_BIT(ctinfo);
+
+       return (sinfo->statemask & statebit);
+}
+
+static int check(const char *tablename,
+                const void *ip,
+                void *matchinfo,
+                unsigned int matchsize,
+                unsigned int hook_mask)
+{
+       if (matchsize != XT_ALIGN(sizeof(struct xt_state_info)))
+               return 0;
+
+       return 1;
+}
+
+static struct xt_match state_match = {
+       .name           = "state",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_match state6_match = {
+       .name           = "state",
+       .match          = &match,
+       .checkentry     = &check,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       need_conntrack();
+
+       ret = xt_register_match(AF_INET, &state_match);
+       if (ret < 0)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &state6_match);
+       if (ret < 0)
+               xt_unregister_match(AF_INET,&state_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &state_match);
+       xt_unregister_match(AF_INET6, &state6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
new file mode 100644 (file)
index 0000000..7c7d5c8
--- /dev/null
@@ -0,0 +1,111 @@
+/* String matching match for iptables
+ * 
+ * (C) 2005 Pablo Neira Ayuso <pablo@eurodev.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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_string.h>
+#include <linux/textsearch.h>
+
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>");
+MODULE_DESCRIPTION("IP tables string match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_string");
+MODULE_ALIAS("ip6t_string");
+
+static int match(const struct sk_buff *skb,
+                const struct net_device *in,
+                const struct net_device *out,
+                const void *matchinfo,
+                int offset,
+                unsigned int protoff,
+                int *hotdrop)
+{
+       struct ts_state state;
+       struct xt_string_info *conf = (struct xt_string_info *) matchinfo;
+
+       memset(&state, 0, sizeof(struct ts_state));
+
+       return (skb_find_text((struct sk_buff *)skb, conf->from_offset, 
+                            conf->to_offset, conf->config, &state) 
+                            != UINT_MAX) && !conf->invert;
+}
+
+#define STRING_TEXT_PRIV(m) ((struct xt_string_info *) m)
+
+static int checkentry(const char *tablename,
+                     const void *ip,
+                     void *matchinfo,
+                     unsigned int matchsize,
+                     unsigned int hook_mask)
+{
+       struct xt_string_info *conf = matchinfo;
+       struct ts_config *ts_conf;
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_string_info)))
+               return 0;
+
+       /* Damn, can't handle this case properly with iptables... */
+       if (conf->from_offset > conf->to_offset)
+               return 0;
+
+       ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
+                                    GFP_KERNEL, TS_AUTOLOAD);
+       if (IS_ERR(ts_conf))
+               return 0;
+
+       conf->config = ts_conf;
+
+       return 1;
+}
+
+static void destroy(void *matchinfo, unsigned int matchsize)
+{
+       textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
+}
+
+static struct xt_match string_match = {
+       .name           = "string",
+       .match          = match,
+       .checkentry     = checkentry,
+       .destroy        = destroy,
+       .me             = THIS_MODULE
+};
+static struct xt_match string6_match = {
+       .name           = "string",
+       .match          = match,
+       .checkentry     = checkentry,
+       .destroy        = destroy,
+       .me             = THIS_MODULE
+};
+
+static int __init init(void)
+{
+       int ret;
+
+       ret = xt_register_match(AF_INET, &string_match);
+       if (ret)
+               return ret;
+       ret = xt_register_match(AF_INET6, &string6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &string_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET, &string_match);
+       xt_unregister_match(AF_INET6, &string6_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
new file mode 100644 (file)
index 0000000..acf7f53
--- /dev/null
@@ -0,0 +1,172 @@
+/* Kernel module to match TCP MSS values. */
+
+/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
+ * Portions (C) 2005 by Harald Welte <laforge@netfilter.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/skbuff.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter/xt_tcpmss.h>
+#include <linux/netfilter/x_tables.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define TH_SYN 0x02
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
+MODULE_DESCRIPTION("iptables TCP MSS match module");
+MODULE_ALIAS("ipt_tcpmss");
+
+/* Returns 1 if the mss option is set and matched by the range, 0 otherwise */
+static inline int
+mssoption_match(u_int16_t min, u_int16_t max,
+               const struct sk_buff *skb,
+               unsigned int protoff,
+               int invert,
+               int *hotdrop)
+{
+       struct tcphdr _tcph, *th;
+       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+       u8 _opt[15 * 4 - sizeof(_tcph)], *op;
+       unsigned int i, optlen;
+
+       /* If we don't have the whole header, drop packet. */
+       th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+       if (th == NULL)
+               goto dropit;
+
+       /* Malformed. */
+       if (th->doff*4 < sizeof(*th))
+               goto dropit;
+
+       optlen = th->doff*4 - sizeof(*th);
+       if (!optlen)
+               goto out;
+
+       /* Truncated options. */
+       op = skb_header_pointer(skb, protoff + sizeof(*th), optlen, _opt);
+       if (op == NULL)
+               goto dropit;
+
+       for (i = 0; i < optlen; ) {
+               if (op[i] == TCPOPT_MSS
+                   && (optlen - i) >= TCPOLEN_MSS
+                   && op[i+1] == TCPOLEN_MSS) {
+                       u_int16_t mssval;
+
+                       mssval = (op[i+2] << 8) | op[i+3];
+                       
+                       return (mssval >= min && mssval <= max) ^ invert;
+               }
+               if (op[i] < 2) i++;
+               else i += op[i+1]?:1;
+       }
+out:
+       return invert;
+
+ dropit:
+       *hotdrop = 1;
+       return 0;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      unsigned int protoff,
+      int *hotdrop)
+{
+       const struct xt_tcpmss_match_info *info = matchinfo;
+
+       return mssoption_match(info->mss_min, info->mss_max, skb, protoff,
+                              info->invert, hotdrop);
+}
+
+static int
+checkentry(const char *tablename,
+           const void *ipinfo,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       const struct ipt_ip *ip = ipinfo;
+       if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
+               return 0;
+
+       /* Must specify -p tcp */
+       if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
+               printk("tcpmss: Only works on TCP packets\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static int
+checkentry6(const char *tablename,
+          const void *ipinfo,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       const struct ip6t_ip6 *ip = ipinfo;
+
+       if (matchsize != XT_ALIGN(sizeof(struct xt_tcpmss_match_info)))
+               return 0;
+
+       /* Must specify -p tcp */
+       if (ip->proto != IPPROTO_TCP || (ip->invflags & XT_INV_PROTO)) {
+               printk("tcpmss: Only works on TCP packets\n");
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_match tcpmss_match = {
+       .name           = "tcpmss",
+       .match          = &match,
+       .checkentry     = &checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_match tcpmss6_match = {
+       .name           = "tcpmss",
+       .match          = &match,
+       .checkentry     = &checkentry6,
+       .me             = THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &tcpmss_match);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &tcpmss6_match);
+       if (ret)
+               xt_unregister_match(AF_INET, &tcpmss_match);
+
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET6, &tcpmss6_match);
+       xt_unregister_match(AF_INET, &tcpmss_match);
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
new file mode 100644 (file)
index 0000000..669c811
--- /dev/null
@@ -0,0 +1,334 @@
+#include <linux/types.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_DESCRIPTION("x_tables match for TCP and UDP, supports IPv4 and IPv6");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("xt_tcp");
+MODULE_ALIAS("xt_udp");
+MODULE_ALIAS("ipt_udp");
+MODULE_ALIAS("ipt_tcp");
+MODULE_ALIAS("ip6t_udp");
+MODULE_ALIAS("ip6t_tcp");
+
+#ifdef DEBUG_IP_FIREWALL_USER
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+
+/* Returns 1 if the port is matched by the range, 0 otherwise */
+static inline int
+port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
+{
+       int ret;
+
+       ret = (port >= min && port <= max) ^ invert;
+       return ret;
+}
+
+static int
+tcp_find_option(u_int8_t option,
+               const struct sk_buff *skb,
+               unsigned int protoff,
+               unsigned int optlen,
+               int invert,
+               int *hotdrop)
+{
+       /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
+       u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
+       unsigned int i;
+
+       duprintf("tcp_match: finding option\n");
+
+       if (!optlen)
+               return invert;
+
+       /* If we don't have the whole header, drop packet. */
+       op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
+                               optlen, _opt);
+       if (op == NULL) {
+               *hotdrop = 1;
+               return 0;
+       }
+
+       for (i = 0; i < optlen; ) {
+               if (op[i] == option) return !invert;
+               if (op[i] < 2) i++;
+               else i += op[i+1]?:1;
+       }
+
+       return invert;
+}
+
+static int
+tcp_match(const struct sk_buff *skb,
+         const struct net_device *in,
+         const struct net_device *out,
+         const void *matchinfo,
+         int offset,
+         unsigned int protoff,
+         int *hotdrop)
+{
+       struct tcphdr _tcph, *th;
+       const struct xt_tcp *tcpinfo = matchinfo;
+
+       if (offset) {
+               /* To quote Alan:
+
+                  Don't allow a fragment of TCP 8 bytes in. Nobody normal
+                  causes this. Its a cracker trying to break in by doing a
+                  flag overwrite to pass the direction checks.
+               */
+               if (offset == 1) {
+                       duprintf("Dropping evil TCP offset=1 frag.\n");
+                       *hotdrop = 1;
+               }
+               /* Must not be a fragment. */
+               return 0;
+       }
+
+#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
+
+       th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
+       if (th == NULL) {
+               /* We've been asked to examine this packet, and we
+                  can't.  Hence, no choice but to drop. */
+               duprintf("Dropping evil TCP offset=0 tinygram.\n");
+               *hotdrop = 1;
+               return 0;
+       }
+
+       if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
+                       ntohs(th->source),
+                       !!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
+               return 0;
+       if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
+                       ntohs(th->dest),
+                       !!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
+               return 0;
+       if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
+                     == tcpinfo->flg_cmp,
+                     XT_TCP_INV_FLAGS))
+               return 0;
+       if (tcpinfo->option) {
+               if (th->doff * 4 < sizeof(_tcph)) {
+                       *hotdrop = 1;
+                       return 0;
+               }
+               if (!tcp_find_option(tcpinfo->option, skb, protoff,
+                                    th->doff*4 - sizeof(_tcph),
+                                    tcpinfo->invflags & XT_TCP_INV_OPTION,
+                                    hotdrop))
+                       return 0;
+       }
+       return 1;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+tcp_checkentry(const char *tablename,
+              const void *info,
+              void *matchinfo,
+              unsigned int matchsize,
+              unsigned int hook_mask)
+{
+       const struct ipt_ip *ip = info;
+       const struct xt_tcp *tcpinfo = matchinfo;
+
+       /* Must specify proto == TCP, and no unknown invflags */
+       return ip->proto == IPPROTO_TCP
+               && !(ip->invflags & XT_INV_PROTO)
+               && matchsize == XT_ALIGN(sizeof(struct xt_tcp))
+               && !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+tcp6_checkentry(const char *tablename,
+              const void *entry,
+              void *matchinfo,
+              unsigned int matchsize,
+              unsigned int hook_mask)
+{
+       const struct ip6t_ip6 *ipv6 = entry;
+       const struct xt_tcp *tcpinfo = matchinfo;
+
+       /* Must specify proto == TCP, and no unknown invflags */
+       return ipv6->proto == IPPROTO_TCP
+               && !(ipv6->invflags & XT_INV_PROTO)
+               && matchsize == XT_ALIGN(sizeof(struct xt_tcp))
+               && !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+}
+
+
+static int
+udp_match(const struct sk_buff *skb,
+         const struct net_device *in,
+         const struct net_device *out,
+         const void *matchinfo,
+         int offset,
+         unsigned int protoff,
+         int *hotdrop)
+{
+       struct udphdr _udph, *uh;
+       const struct xt_udp *udpinfo = matchinfo;
+
+       /* Must not be a fragment. */
+       if (offset)
+               return 0;
+
+       uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
+       if (uh == NULL) {
+               /* We've been asked to examine this packet, and we
+                  can't.  Hence, no choice but to drop. */
+               duprintf("Dropping evil UDP tinygram.\n");
+               *hotdrop = 1;
+               return 0;
+       }
+
+       return port_match(udpinfo->spts[0], udpinfo->spts[1],
+                         ntohs(uh->source),
+                         !!(udpinfo->invflags & XT_UDP_INV_SRCPT))
+               && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
+                             ntohs(uh->dest),
+                             !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+udp_checkentry(const char *tablename,
+              const void *info,
+              void *matchinfo,
+              unsigned int matchinfosize,
+              unsigned int hook_mask)
+{
+       const struct ipt_ip *ip = info;
+       const struct xt_udp *udpinfo = matchinfo;
+
+       /* Must specify proto == UDP, and no unknown invflags */
+       if (ip->proto != IPPROTO_UDP || (ip->invflags & XT_INV_PROTO)) {
+               duprintf("ipt_udp: Protocol %u != %u\n", ip->proto,
+                        IPPROTO_UDP);
+               return 0;
+       }
+       if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
+               duprintf("ipt_udp: matchsize %u != %u\n",
+                        matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
+               return 0;
+       }
+       if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
+               duprintf("ipt_udp: unknown flags %X\n",
+                        udpinfo->invflags);
+               return 0;
+       }
+
+       return 1;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+udp6_checkentry(const char *tablename,
+              const void *entry,
+              void *matchinfo,
+              unsigned int matchinfosize,
+              unsigned int hook_mask)
+{
+       const struct ip6t_ip6 *ipv6 = entry;
+       const struct xt_udp *udpinfo = matchinfo;
+
+       /* Must specify proto == UDP, and no unknown invflags */
+       if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & XT_INV_PROTO)) {
+               duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
+                        IPPROTO_UDP);
+               return 0;
+       }
+       if (matchinfosize != XT_ALIGN(sizeof(struct xt_udp))) {
+               duprintf("ip6t_udp: matchsize %u != %u\n",
+                        matchinfosize, XT_ALIGN(sizeof(struct xt_udp)));
+               return 0;
+       }
+       if (udpinfo->invflags & ~XT_UDP_INV_MASK) {
+               duprintf("ip6t_udp: unknown flags %X\n",
+                        udpinfo->invflags);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct xt_match tcp_matchstruct = {
+       .name           = "tcp",
+       .match          = &tcp_match,
+       .checkentry     = &tcp_checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match tcp6_matchstruct = {
+       .name           = "tcp",
+       .match          = &tcp_match,
+       .checkentry     = &tcp6_checkentry,
+       .me             = THIS_MODULE,
+};
+
+static struct xt_match udp_matchstruct = {
+       .name           = "udp",
+       .match          = &udp_match,
+       .checkentry     = &udp_checkentry,
+       .me             = THIS_MODULE,
+};
+static struct xt_match udp6_matchstruct = {
+       .name           = "udp",
+       .match          = &udp_match,
+       .checkentry     = &udp6_checkentry,
+       .me             = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+       int ret;
+       ret = xt_register_match(AF_INET, &tcp_matchstruct);
+       if (ret)
+               return ret;
+
+       ret = xt_register_match(AF_INET6, &tcp6_matchstruct);
+       if (ret)
+               goto out_unreg_tcp;
+
+       ret = xt_register_match(AF_INET, &udp_matchstruct);
+       if (ret)
+               goto out_unreg_tcp6;
+       
+       ret = xt_register_match(AF_INET6, &udp6_matchstruct);
+       if (ret)
+               goto out_unreg_udp;
+
+       return ret;
+
+out_unreg_udp:
+       xt_unregister_match(AF_INET, &tcp_matchstruct);
+out_unreg_tcp6:
+       xt_unregister_match(AF_INET6, &tcp6_matchstruct);
+out_unreg_tcp:
+       xt_unregister_match(AF_INET, &tcp_matchstruct);
+       return ret;
+}
+
+static void __exit fini(void)
+{
+       xt_unregister_match(AF_INET6, &udp6_matchstruct);
+       xt_unregister_match(AF_INET, &udp_matchstruct);
+       xt_unregister_match(AF_INET6, &tcp6_matchstruct);
+       xt_unregister_match(AF_INET, &tcp_matchstruct);
+}
+
+module_init(init);
+module_exit(fini);
index 3b1378498d50b12647f2ea433a341b16502e1ac9..4ae1538c54a9397505d8ae3e74eb19eba6c50337 100644 (file)
@@ -222,11 +222,6 @@ int genl_register_family(struct genl_family *family)
                goto errout_locked;
        }
 
-       if (!try_module_get(family->owner)) {
-               err = -EBUSY;
-               goto errout_locked;
-       }
-
        if (family->id == GENL_ID_GENERATE) {
                u16 newid = genl_generate_id();
 
@@ -283,7 +278,6 @@ int genl_unregister_family(struct genl_family *family)
                INIT_LIST_HEAD(&family->ops_list);
                genl_unlock();
 
-               module_put(family->owner);
                kfree(family->attrbuf);
                genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
                return 0;
@@ -535,7 +529,6 @@ static struct genl_family genl_ctrl = {
        .name = "nlctrl",
        .version = 0x1,
        .maxattr = CTRL_ATTR_MAX,
-       .owner = THIS_MODULE,
 };
 
 static int __init genl_init(void)
index 8a260d43ceef156d89389aa1dbb388f93c0c7a91..778b1e5a4b50976196677b4b7bb51dd13345c921 100644 (file)
@@ -44,7 +44,7 @@ if NET_SCHED
 
 choice
        prompt "Packet scheduler clock source"
-       default NET_SCH_CLK_JIFFIES
+       default NET_SCH_CLK_GETTIMEOFDAY
        ---help---
          Packet schedulers need a monotonic clock that increments at a static
          rate. The kernel provides several suitable interfaces, each with
index b5001939b74b59822291de1b0f5759164da29f2b..39a22a3ffe78822636cad6306536916c368e5f19 100644 (file)
@@ -62,7 +62,7 @@ ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook)
        struct ipt_target *target;
        int ret = 0;
 
-       target = ipt_find_target(t->u.user.name, t->u.user.revision);
+       target = xt_find_target(AF_INET, t->u.user.name, t->u.user.revision);
        if (!target)
                return -ENOENT;
 
index 04c7fab4edc42b49068513a455ca2c747b174f8e..2e266129a764d2f0dc0edfaabdf483155b8cfdb1 100644 (file)
@@ -180,8 +180,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
        }
 
        SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
-                         "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-                         "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                         "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
                          __FUNCTION__, skb, skb->len,
                          NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
 
@@ -206,13 +205,13 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
                fl.oif = daddr->v6.sin6_scope_id;
        
 
-       SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+       SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
                          __FUNCTION__, NIP6(fl.fl6_dst));
 
        if (saddr) {
                ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
                SCTP_DEBUG_PRINTK(
-                       "SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
+                       "SRC=" NIP6_FMT " - ",
                        NIP6(fl.fl6_src));
        }
 
@@ -221,8 +220,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
                struct rt6_info *rt;
                rt = (struct rt6_info *)dst;
                SCTP_DEBUG_PRINTK(
-                       "rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
-                       "rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                       "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
                        NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
        } else {
                SCTP_DEBUG_PRINTK("NO ROUTE\n");
@@ -271,13 +269,12 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
        __u8 bmatchlen;
 
        SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
-                         "daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+                         "daddr:" NIP6_FMT " ",
                          __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
        if (!asoc) {
                ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
-               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
-                                 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+               SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
                                  NIP6(saddr->v6.sin6_addr));
                return;
        }
@@ -305,13 +302,11 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
 
        if (baddr) {
                memcpy(saddr, baddr, sizeof(union sctp_addr));
-               SCTP_DEBUG_PRINTK("saddr: "
-                                 "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+               SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
                                  NIP6(saddr->v6.sin6_addr));
        } else {
                printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
-                      "address for the "
-                      "dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                      "address for the dest:" NIP6_FMT "\n",
                       __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
        }
 
@@ -675,8 +670,7 @@ static int sctp_v6_is_ce(const struct sk_buff *skb)
 /* Dump the v6 addr to the seq file. */
 static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
 {
-       seq_printf(seq, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
-                  NIP6(addr->v6.sin6_addr));
+       seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
 }
 
 /* Initialize a PF_INET6 socket msg_name. */
index 557a7d90b92a1a9f5c31430d81d2ed3a7222d3b5..477d7f80dba686713ac6b10288f343a581e1ba5b 100644 (file)
@@ -1036,14 +1036,14 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
                if (from_addr.sa.sa_family == AF_INET6) {
                        printk(KERN_WARNING
                               "%s association %p could not find address "
-                              "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+                              NIP6_FMT "\n",
                               __FUNCTION__,
                               asoc,
                               NIP6(from_addr.v6.sin6_addr));
                } else {
                        printk(KERN_WARNING
                               "%s association %p could not find address "
-                              "%u.%u.%u.%u\n",
+                              NIPQUAD_FMT "\n",
                               __FUNCTION__,
                               asoc,
                               NIPQUAD(from_addr.v4.sin_addr.s_addr));
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
new file mode 100644 (file)
index 0000000..05ab18e
--- /dev/null
@@ -0,0 +1,112 @@
+#
+# TIPC configuration
+#
+
+menu "TIPC Configuration (EXPERIMENTAL)"
+       depends on INET && EXPERIMENTAL
+
+config TIPC
+       tristate "The TIPC Protocol (EXPERIMENTAL)"
+       ---help---
+         TBD.
+
+         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>.
+
+         If in doubt, say N.
+
+config TIPC_ADVANCED
+       bool "TIPC: Advanced configuration"
+       depends on TIPC
+       default n
+       help
+         Saying Y here will open some advanced configuration
+          for TIPC. Most users do not need to bother, so if
+          unsure, just say N.
+
+config TIPC_ZONES
+       int "Maximum number of zones in network"
+       depends on TIPC && TIPC_ADVANCED
+       default "3"
+       help
+        Max number of zones inside TIPC network. Max supported value 
+         is 255 zones, minimum is 1
+
+        Default is 3 zones in a network; setting this to higher
+        allows more zones but might use more memory.
+
+config TIPC_CLUSTERS
+       int "Maximum number of clusters in a zone"
+       depends on TIPC && TIPC_ADVANCED
+       default "1"
+       help
+          ***Only 1 (one cluster in a zone) is supported by current code.
+          Any value set here will be overridden.***
+
+          (Max number of clusters inside TIPC zone. Max supported 
+          value is 4095 clusters, minimum is 1.
+
+         Default is 1; setting this to smaller value might save 
+          some memory, setting it to higher
+         allows more clusters and might consume more memory.)
+
+config TIPC_NODES
+       int "Maximum number of nodes in cluster"
+       depends on TIPC && TIPC_ADVANCED
+       default "255"
+       help
+         Maximum number of nodes inside a TIPC cluster. Maximum 
+          supported value is 2047 nodes, minimum is 8. 
+
+         Setting this to a smaller value saves some memory, 
+         setting it to higher allows more nodes.
+
+config TIPC_SLAVE_NODES
+       int "Maximum number of slave nodes in cluster"
+       depends on TIPC && TIPC_ADVANCED
+       default "0"
+       help
+          ***This capability is not supported by current code.***
+         
+         Maximum number of slave nodes inside a TIPC cluster. Maximum 
+          supported value is 2047 nodes, minimum is 0. 
+
+         Setting this to a smaller value saves some memory, 
+         setting it to higher allows more nodes.
+
+config TIPC_PORTS
+       int "Maximum number of ports in a node"
+       depends on TIPC && TIPC_ADVANCED
+       default "8191"
+       help
+         Maximum number of ports within a node. Maximum 
+          supported value is 64535 nodes, minimum is 127. 
+
+         Setting this to a smaller value saves some memory, 
+         setting it to higher allows more ports.
+
+config TIPC_LOG
+       int "Size of log buffer"
+       depends on TIPC && TIPC_ADVANCED
+       default 0
+       help
+         Size (in bytes) of TIPC's internal log buffer, which records the
+         occurrence of significant events.  Maximum supported value
+         is 32768 bytes, minimum is 0.
+
+         There is no need to enable the log buffer unless the node will be
+         managed remotely via TIPC.
+
+config TIPC_DEBUG
+       bool "Enable debugging support"
+       depends on TIPC
+       default n
+       help
+         This will enable debugging of TIPC.
+
+         Only say Y here if you are having trouble with TIPC.  It will
+         enable the display of detailed information about what is going on.
+
+endmenu
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
new file mode 100644 (file)
index 0000000..dceb702
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for the Linux TIPC layer
+#
+
+obj-$(CONFIG_TIPC) := tipc.o
+
+tipc-y += addr.o bcast.o bearer.o config.o cluster.o \
+          core.o handler.o link.o discover.o msg.o  \
+          name_distr.o  subscr.o name_table.o net.o  \
+          netlink.o node.o node_subscr.o port.o ref.o  \
+          socket.o user_reg.o zone.o dbg.o eth_media.o
+
+# End of file
diff --git a/net/tipc/addr.c b/net/tipc/addr.c
new file mode 100644 (file)
index 0000000..eca2226
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * net/tipc/addr.c: TIPC address utility routines
+ *     
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "addr.h"
+#include "zone.h"
+#include "cluster.h"
+#include "net.h"
+
+u32 tipc_get_addr(void)
+{
+       return tipc_own_addr;
+}
+
+/**
+ * addr_domain_valid - validates a network domain address
+ * 
+ * Accepts <Z.C.N>, <Z.C.0>, <Z.0.0>, and <0.0.0>, 
+ * where Z, C, and N are non-zero and do not exceed the configured limits.
+ * 
+ * Returns 1 if domain address is valid, otherwise 0
+ */
+
+int addr_domain_valid(u32 addr)
+{
+       u32 n = tipc_node(addr);
+       u32 c = tipc_cluster(addr);
+       u32 z = tipc_zone(addr);
+       u32 max_nodes = tipc_max_nodes;
+
+       if (is_slave(addr))
+               max_nodes = LOWEST_SLAVE + tipc_max_slaves;
+       if (n > max_nodes)
+               return 0;
+       if (c > tipc_max_clusters)
+               return 0;
+       if (z > tipc_max_zones)
+               return 0;
+
+       if (n && (!z || !c))
+               return 0;
+       if (c && !z)
+               return 0;
+       return 1;
+}
+
+/**
+ * addr_node_valid - validates a proposed network address for this node
+ * 
+ * Accepts <Z.C.N>, where Z, C, and N are non-zero and do not exceed 
+ * the configured limits.
+ * 
+ * Returns 1 if address can be used, otherwise 0
+ */
+
+int addr_node_valid(u32 addr)
+{
+       return (addr_domain_valid(addr) && tipc_node(addr));
+}
+
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
new file mode 100644 (file)
index 0000000..02ca717
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * net/tipc/addr.h: Include file for TIPC address utility routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_ADDR_H
+#define _TIPC_ADDR_H
+
+static inline u32 own_node(void)
+{
+       return tipc_node(tipc_own_addr);
+}
+
+static inline u32 own_cluster(void)
+{
+       return tipc_cluster(tipc_own_addr);
+}
+
+static inline u32 own_zone(void)
+{
+       return tipc_zone(tipc_own_addr);
+}
+
+static inline int in_own_cluster(u32 addr)
+{
+       return !((addr ^ tipc_own_addr) >> 12);
+}
+
+static inline int in_own_zone(u32 addr)
+{
+       return !((addr ^ tipc_own_addr) >> 24);
+}
+
+static inline int is_slave(u32 addr)
+{
+       return addr & 0x800;
+}
+
+static inline int may_route(u32 addr)
+{
+       return(addr ^ tipc_own_addr) >> 11;
+}
+
+static inline int in_scope(u32 domain, u32 addr)
+{
+       if (!domain || (domain == addr))
+               return 1;
+       if (domain == (addr & 0xfffff000u)) /* domain <Z.C.0> */
+               return 1;
+       if (domain == (addr & 0xff000000u)) /* domain <Z.0.0> */
+               return 1;
+       return 0;
+}
+
+/**
+ * addr_scope - convert message lookup domain to equivalent 2-bit scope value
+ */
+
+static inline int addr_scope(u32 domain)
+{
+       if (likely(!domain))
+               return TIPC_ZONE_SCOPE;
+       if (tipc_node(domain))
+               return TIPC_NODE_SCOPE;
+       if (tipc_cluster(domain))
+               return TIPC_CLUSTER_SCOPE;
+       return TIPC_ZONE_SCOPE;
+}
+
+/**
+ * addr_domain - convert 2-bit scope value to equivalent message lookup domain
+ *  
+ * Needed when address of a named message must be looked up a second time 
+ * after a network hop.
+ */
+
+static inline int addr_domain(int sc)
+{
+       if (likely(sc == TIPC_NODE_SCOPE))
+               return tipc_own_addr;
+       if (sc == TIPC_CLUSTER_SCOPE)
+               return tipc_addr(tipc_zone(tipc_own_addr),
+                                tipc_cluster(tipc_own_addr), 0);
+       return tipc_addr(tipc_zone(tipc_own_addr), 0, 0);
+}
+
+static inline char *addr_string_fill(char *string, u32 addr)
+{
+       snprintf(string, 16, "<%u.%u.%u>",
+                tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
+       return string;
+}
+
+int addr_domain_valid(u32);
+int addr_node_valid(u32 addr);
+
+#endif
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
new file mode 100644 (file)
index 0000000..9713d62
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * net/tipc/bcast.c: TIPC broadcast code
+ *     
+ * Copyright (c) 2004-2006, Ericsson AB
+ * Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "msg.h"
+#include "dbg.h"
+#include "link.h"
+#include "net.h"
+#include "node.h"
+#include "port.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "name_distr.h"
+#include "bearer.h"
+#include "name_table.h"
+#include "bcast.h"
+
+
+#define MAX_PKT_DEFAULT_MCAST 1500     /* bcast link max packet size (fixed) */
+
+#define BCLINK_WIN_DEFAULT 20          /* bcast link window size (default) */
+
+#define BCLINK_LOG_BUF_SIZE 0
+
+/**
+ * struct bcbearer_pair - a pair of bearers used by broadcast link
+ * @primary: pointer to primary bearer
+ * @secondary: pointer to secondary bearer
+ * 
+ * Bearers must have same priority and same set of reachable destinations 
+ * to be paired.
+ */
+
+struct bcbearer_pair {
+       struct bearer *primary;
+       struct bearer *secondary;
+};
+
+/**
+ * struct bcbearer - bearer used by broadcast link
+ * @bearer: (non-standard) broadcast bearer structure
+ * @media: (non-standard) broadcast media structure
+ * @bpairs: array of bearer pairs
+ * @bpairs_temp: array of bearer pairs used during creation of "bpairs"
+ */
+
+struct bcbearer {
+       struct bearer bearer;
+       struct media media;
+       struct bcbearer_pair bpairs[MAX_BEARERS];
+       struct bcbearer_pair bpairs_temp[TIPC_NUM_LINK_PRI];
+};
+
+/**
+ * struct bclink - link used for broadcast messages
+ * @link: (non-standard) broadcast link structure
+ * @node: (non-standard) node structure representing b'cast link's peer node
+ * 
+ * Handles sequence numbering, fragmentation, bundling, etc.
+ */
+
+struct bclink {
+       struct link link;
+       struct node node;
+};
+
+
+static struct bcbearer *bcbearer = NULL;
+static struct bclink *bclink = NULL;
+static struct link *bcl = NULL;
+static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
+
+char bc_link_name[] = "multicast-link";
+
+
+static inline u32 buf_seqno(struct sk_buff *buf)
+{
+       return msg_seqno(buf_msg(buf));
+} 
+
+static inline u32 bcbuf_acks(struct sk_buff *buf)
+{
+       return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle;
+}
+
+static inline void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
+{
+       TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)acks;
+}
+
+static inline void bcbuf_decr_acks(struct sk_buff *buf)
+{
+       bcbuf_set_acks(buf, bcbuf_acks(buf) - 1);
+}
+
+
+/** 
+ * bclink_set_gap - set gap according to contents of current deferred pkt queue
+ * 
+ * Called with 'node' locked, bc_lock unlocked
+ */
+
+static inline void bclink_set_gap(struct node *n_ptr)
+{
+       struct sk_buff *buf = n_ptr->bclink.deferred_head;
+
+       n_ptr->bclink.gap_after = n_ptr->bclink.gap_to =
+               mod(n_ptr->bclink.last_in);
+       if (unlikely(buf != NULL))
+               n_ptr->bclink.gap_to = mod(buf_seqno(buf) - 1);
+}
+
+/** 
+ * bclink_ack_allowed - test if ACK or NACK message can be sent at this moment
+ * 
+ * This mechanism endeavours to prevent all nodes in network from trying
+ * to ACK or NACK at the same time.
+ * 
+ * Note: TIPC uses a different trigger to distribute ACKs than it does to
+ *       distribute NACKs, but tries to use the same spacing (divide by 16). 
+ */
+
+static inline int bclink_ack_allowed(u32 n)
+{
+       return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag);
+}
+
+
+/** 
+ * bclink_retransmit_pkt - retransmit broadcast packets
+ * @after: sequence number of last packet to *not* retransmit
+ * @to: sequence number of last packet to retransmit
+ * 
+ * Called with 'node' locked, bc_lock unlocked
+ */
+
+static void bclink_retransmit_pkt(u32 after, u32 to)
+{
+       struct sk_buff *buf;
+
+       spin_lock_bh(&bc_lock);
+       buf = bcl->first_out;
+       while (buf && less_eq(buf_seqno(buf), after)) {
+               buf = buf->next;                
+       }
+       if (buf != NULL)
+               link_retransmit(bcl, buf, mod(to - after));
+       spin_unlock_bh(&bc_lock);              
+}
+
+/** 
+ * bclink_acknowledge - handle acknowledgement of broadcast packets
+ * @n_ptr: node that sent acknowledgement info
+ * @acked: broadcast sequence # that has been acknowledged
+ * 
+ * Node is locked, bc_lock unlocked.
+ */
+
+void bclink_acknowledge(struct node *n_ptr, u32 acked)
+{
+       struct sk_buff *crs;
+       struct sk_buff *next;
+       unsigned int released = 0;
+
+       if (less_eq(acked, n_ptr->bclink.acked))
+               return;
+
+       spin_lock_bh(&bc_lock);
+
+       /* Skip over packets that node has previously acknowledged */
+
+       crs = bcl->first_out;
+       while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked)) {
+               crs = crs->next;
+       }
+
+       /* Update packets that node is now acknowledging */
+
+       while (crs && less_eq(buf_seqno(crs), acked)) {
+               next = crs->next;
+               bcbuf_decr_acks(crs);
+               if (bcbuf_acks(crs) == 0) {
+                       bcl->first_out = next;
+                       bcl->out_queue_size--;
+                       buf_discard(crs);
+                       released = 1;
+               }
+               crs = next;
+       }
+       n_ptr->bclink.acked = acked;
+
+       /* Try resolving broadcast link congestion, if necessary */
+
+       if (unlikely(bcl->next_out))
+               link_push_queue(bcl);
+       if (unlikely(released && !list_empty(&bcl->waiting_ports)))
+               link_wakeup_ports(bcl, 0);
+       spin_unlock_bh(&bc_lock);
+}
+
+/** 
+ * bclink_send_ack - unicast an ACK msg
+ * 
+ * net_lock and node lock set
+ */
+
+static void bclink_send_ack(struct node *n_ptr)
+{
+       struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
+
+       if (l_ptr != NULL)
+               link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+}
+
+/** 
+ * bclink_send_nack- broadcast a NACK msg
+ * 
+ * net_lock and node lock set
+ */
+
+static void bclink_send_nack(struct node *n_ptr)
+{
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+
+       if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to))
+               return;
+
+       buf = buf_acquire(INT_H_SIZE);
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
+                        TIPC_OK, INT_H_SIZE, n_ptr->addr);
+               msg_set_mc_netid(msg, tipc_net_id);
+               msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in)); 
+               msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
+               msg_set_bcgap_to(msg, n_ptr->bclink.gap_to);
+               msg_set_bcast_tag(msg, tipc_own_tag);
+
+               if (bearer_send(&bcbearer->bearer, buf, 0)) {
+                       bcl->stats.sent_nacks++;
+                       buf_discard(buf);
+               } else {
+                       bearer_schedule(bcl->b_ptr, bcl);
+                       bcl->proto_msg_queue = buf;
+                       bcl->stats.bearer_congs++;
+               }
+
+               /* 
+                * Ensure we doesn't send another NACK msg to the node
+                * until 16 more deferred messages arrive from it
+                * (i.e. helps prevent all nodes from NACK'ing at same time)
+                */
+               
+               n_ptr->bclink.nack_sync = tipc_own_tag;
+       }
+}
+
+/** 
+ * bclink_check_gap - send a NACK if a sequence gap exists
+ *
+ * net_lock and node lock set
+ */
+
+void bclink_check_gap(struct node *n_ptr, u32 last_sent)
+{
+       if (!n_ptr->bclink.supported ||
+           less_eq(last_sent, mod(n_ptr->bclink.last_in)))
+               return;
+
+       bclink_set_gap(n_ptr);
+       if (n_ptr->bclink.gap_after == n_ptr->bclink.gap_to)
+               n_ptr->bclink.gap_to = last_sent;
+       bclink_send_nack(n_ptr);
+}
+
+/** 
+ * bclink_peek_nack - process a NACK msg meant for another node
+ * 
+ * Only net_lock set.
+ */
+
+void bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
+{
+       struct node *n_ptr = node_find(dest);
+       u32 my_after, my_to;
+
+       if (unlikely(!n_ptr || !node_is_up(n_ptr)))
+               return;
+       node_lock(n_ptr);
+       /*
+        * Modify gap to suppress unnecessary NACKs from this node
+        */
+       my_after = n_ptr->bclink.gap_after;
+       my_to = n_ptr->bclink.gap_to;
+
+       if (less_eq(gap_after, my_after)) {
+               if (less(my_after, gap_to) && less(gap_to, my_to))
+                       n_ptr->bclink.gap_after = gap_to;
+               else if (less_eq(my_to, gap_to))
+                       n_ptr->bclink.gap_to = n_ptr->bclink.gap_after;
+       } else if (less_eq(gap_after, my_to)) {
+               if (less_eq(my_to, gap_to))
+                       n_ptr->bclink.gap_to = gap_after;
+       } else {
+               /* 
+                * Expand gap if missing bufs not in deferred queue:
+                */
+               struct sk_buff *buf = n_ptr->bclink.deferred_head;
+               u32 prev = n_ptr->bclink.gap_to;
+
+               for (; buf; buf = buf->next) {
+                       u32 seqno = buf_seqno(buf);
+
+                       if (mod(seqno - prev) != 1)
+                               buf = NULL;
+                       if (seqno == gap_after)
+                               break;
+                       prev = seqno;
+               }
+               if (buf == NULL)
+                       n_ptr->bclink.gap_to = gap_after;
+       }
+       /*
+        * Some nodes may send a complementary NACK now:
+        */ 
+       if (bclink_ack_allowed(sender_tag + 1)) {
+               if (n_ptr->bclink.gap_to != n_ptr->bclink.gap_after) {
+                       bclink_send_nack(n_ptr);
+                       bclink_set_gap(n_ptr);
+               }
+       }
+       node_unlock(n_ptr);
+}
+
+/**
+ * bclink_send_msg - broadcast a packet to all nodes in cluster
+ */
+
+int bclink_send_msg(struct sk_buff *buf)
+{
+       int res;
+
+       spin_lock_bh(&bc_lock);
+
+       res = link_send_buf(bcl, buf);
+       if (unlikely(res == -ELINKCONG))
+               buf_discard(buf);
+       else
+               bcl->stats.sent_info++;
+
+       if (bcl->out_queue_size > bcl->stats.max_queue_sz)
+               bcl->stats.max_queue_sz = bcl->out_queue_size;
+       bcl->stats.queue_sz_counts++;
+       bcl->stats.accu_queue_sz += bcl->out_queue_size;
+
+       spin_unlock_bh(&bc_lock);
+       return res;
+}
+
+/**
+ * bclink_recv_pkt - receive a broadcast packet, and deliver upwards
+ * 
+ * net_lock is read_locked, no other locks set
+ */
+
+void bclink_recv_pkt(struct sk_buff *buf)
+{        
+       struct tipc_msg *msg = buf_msg(buf);
+       struct node* node = node_find(msg_prevnode(msg));
+       u32 next_in;
+       u32 seqno;
+       struct sk_buff *deferred;
+
+       msg_dbg(msg, "<BC<<<");
+
+       if (unlikely(!node || !node_is_up(node) || !node->bclink.supported || 
+                    (msg_mc_netid(msg) != tipc_net_id))) {
+               buf_discard(buf);
+               return;
+       }
+
+       if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
+               msg_dbg(msg, "<BCNACK<<<");
+               if (msg_destnode(msg) == tipc_own_addr) {
+                       node_lock(node);
+                       bclink_acknowledge(node, msg_bcast_ack(msg));
+                       node_unlock(node);
+                       bcl->stats.recv_nacks++;
+                       bclink_retransmit_pkt(msg_bcgap_after(msg),
+                                             msg_bcgap_to(msg));
+               } else {
+                       bclink_peek_nack(msg_destnode(msg),
+                                        msg_bcast_tag(msg),
+                                        msg_bcgap_after(msg),
+                                        msg_bcgap_to(msg));
+               }
+               buf_discard(buf);
+               return;
+       }
+
+       node_lock(node);
+receive:
+       deferred = node->bclink.deferred_head;
+       next_in = mod(node->bclink.last_in + 1);
+       seqno = msg_seqno(msg);
+
+       if (likely(seqno == next_in)) {
+               bcl->stats.recv_info++;
+               node->bclink.last_in++;
+               bclink_set_gap(node);
+               if (unlikely(bclink_ack_allowed(seqno))) {
+                       bclink_send_ack(node);
+                       bcl->stats.sent_acks++;
+               }
+               if (likely(msg_isdata(msg))) {
+                       node_unlock(node);
+                       port_recv_mcast(buf, NULL);
+               } else if (msg_user(msg) == MSG_BUNDLER) {
+                       bcl->stats.recv_bundles++;
+                       bcl->stats.recv_bundled += msg_msgcnt(msg);
+                       node_unlock(node);
+                       link_recv_bundle(buf);
+               } else if (msg_user(msg) == MSG_FRAGMENTER) {
+                       bcl->stats.recv_fragments++;
+                       if (link_recv_fragment(&node->bclink.defragm,
+                                              &buf, &msg))
+                               bcl->stats.recv_fragmented++;
+                       node_unlock(node);
+                       net_route_msg(buf);
+               } else {
+                       node_unlock(node);
+                       net_route_msg(buf);
+               }
+               if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
+                       node_lock(node);
+                       buf = deferred;
+                       msg = buf_msg(buf);
+                       node->bclink.deferred_head = deferred->next;
+                       goto receive;
+               }
+               return;
+       } else if (less(next_in, seqno)) {
+               u32 gap_after = node->bclink.gap_after;
+               u32 gap_to = node->bclink.gap_to;
+
+               if (link_defer_pkt(&node->bclink.deferred_head,
+                                  &node->bclink.deferred_tail,
+                                  buf)) {
+                       node->bclink.nack_sync++;
+                       bcl->stats.deferred_recv++;
+                       if (seqno == mod(gap_after + 1))
+                               node->bclink.gap_after = seqno;
+                       else if (less(gap_after, seqno) && less(seqno, gap_to))
+                               node->bclink.gap_to = seqno;
+               }
+               if (bclink_ack_allowed(node->bclink.nack_sync)) {
+                       if (gap_to != gap_after)
+                               bclink_send_nack(node);
+                       bclink_set_gap(node);
+               }
+       } else {
+               bcl->stats.duplicates++;
+               buf_discard(buf);
+       }
+       node_unlock(node);
+}
+
+u32 bclink_get_last_sent(void)
+{
+       u32 last_sent = mod(bcl->next_out_no - 1);
+
+       if (bcl->next_out)
+               last_sent = mod(buf_seqno(bcl->next_out) - 1);
+       return last_sent;
+}
+
+u32 bclink_acks_missing(struct node *n_ptr)
+{
+       return (n_ptr->bclink.supported &&
+               (bclink_get_last_sent() != n_ptr->bclink.acked));
+}
+
+
+/**
+ * bcbearer_send - send a packet through the broadcast pseudo-bearer
+ * 
+ * Send through as many bearers as necessary to reach all nodes
+ * that support TIPC multicasting.
+ * 
+ * Returns 0 if packet sent successfully, non-zero if not
+ */
+
+int bcbearer_send(struct sk_buff *buf,
+                 struct tipc_bearer *unused1,
+                 struct tipc_media_addr *unused2)
+{
+       static int send_count = 0;
+
+       struct node_map remains;
+       struct node_map remains_new;
+       int bp_index;
+       int swap_time;
+
+       /* Prepare buffer for broadcasting (if first time trying to send it) */
+
+       if (likely(!msg_non_seq(buf_msg(buf)))) {
+               struct tipc_msg *msg;
+
+               assert(cluster_bcast_nodes.count != 0);
+               bcbuf_set_acks(buf, cluster_bcast_nodes.count);
+               msg = buf_msg(buf);
+               msg_set_non_seq(msg);
+               msg_set_mc_netid(msg, tipc_net_id);
+       }
+
+       /* Determine if bearer pairs should be swapped following this attempt */
+
+       if ((swap_time = (++send_count >= 10)))
+               send_count = 0;
+
+       /* Send buffer over bearers until all targets reached */
+       
+       remains = cluster_bcast_nodes;
+
+       for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
+               struct bearer *p = bcbearer->bpairs[bp_index].primary;
+               struct bearer *s = bcbearer->bpairs[bp_index].secondary;
+
+               if (!p)
+                       break;  /* no more bearers to try */
+
+               nmap_diff(&remains, &p->nodes, &remains_new);
+               if (remains_new.count == remains.count)
+                       continue;       /* bearer pair doesn't add anything */
+
+               if (!p->publ.blocked &&
+                   !p->media->send_msg(buf, &p->publ, &p->media->bcast_addr)) {
+                       if (swap_time && s && !s->publ.blocked)
+                               goto swap;
+                       else
+                               goto update;
+               }
+
+               if (!s || s->publ.blocked ||
+                   s->media->send_msg(buf, &s->publ, &s->media->bcast_addr))
+                       continue;       /* unable to send using bearer pair */
+swap:
+               bcbearer->bpairs[bp_index].primary = s;
+               bcbearer->bpairs[bp_index].secondary = p;
+update:
+               if (remains_new.count == 0)
+                       return TIPC_OK;
+
+               remains = remains_new;
+       }
+       
+       /* Unable to reach all targets */
+
+       bcbearer->bearer.publ.blocked = 1;
+       bcl->stats.bearer_congs++;
+       return ~TIPC_OK;
+}
+
+/**
+ * bcbearer_sort - create sets of bearer pairs used by broadcast bearer
+ */
+
+void bcbearer_sort(void)
+{
+       struct bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
+       struct bcbearer_pair *bp_curr;
+       int b_index;
+       int pri;
+
+       spin_lock_bh(&bc_lock);
+
+       /* Group bearers by priority (can assume max of two per priority) */
+
+       memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
+
+       for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
+               struct bearer *b = &bearers[b_index];
+
+               if (!b->active || !b->nodes.count)
+                       continue;
+
+               if (!bp_temp[b->priority].primary)
+                       bp_temp[b->priority].primary = b;
+               else
+                       bp_temp[b->priority].secondary = b;
+       }
+
+       /* Create array of bearer pairs for broadcasting */
+
+       bp_curr = bcbearer->bpairs;
+       memset(bcbearer->bpairs, 0, sizeof(bcbearer->bpairs));
+
+       for (pri = (TIPC_NUM_LINK_PRI - 1); pri >= 0; pri--) {
+
+               if (!bp_temp[pri].primary)
+                       continue;
+
+               bp_curr->primary = bp_temp[pri].primary;
+
+               if (bp_temp[pri].secondary) {
+                       if (nmap_equal(&bp_temp[pri].primary->nodes,
+                                      &bp_temp[pri].secondary->nodes)) {
+                               bp_curr->secondary = bp_temp[pri].secondary;
+                       } else {
+                               bp_curr++;
+                               bp_curr->primary = bp_temp[pri].secondary;
+                       }
+               }
+
+               bp_curr++;
+       }
+
+       spin_unlock_bh(&bc_lock);
+}
+
+/**
+ * bcbearer_push - resolve bearer congestion
+ * 
+ * Forces bclink to push out any unsent packets, until all packets are gone
+ * or congestion reoccurs.
+ * No locks set when function called
+ */
+
+void bcbearer_push(void)
+{
+       struct bearer *b_ptr;
+
+       spin_lock_bh(&bc_lock);
+       b_ptr = &bcbearer->bearer;
+       if (b_ptr->publ.blocked) {
+               b_ptr->publ.blocked = 0;
+               bearer_lock_push(b_ptr);
+       }
+       spin_unlock_bh(&bc_lock);
+}
+
+
+int bclink_stats(char *buf, const u32 buf_size)
+{
+       struct print_buf pb;
+
+       if (!bcl)
+               return 0;
+
+       printbuf_init(&pb, buf, buf_size);
+
+       spin_lock_bh(&bc_lock);
+
+       tipc_printf(&pb, "Link <%s>\n"
+                        "  Window:%u packets\n", 
+                   bcl->name, bcl->queue_limit[0]);
+       tipc_printf(&pb, "  RX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+                   bcl->stats.recv_info,
+                   bcl->stats.recv_fragments,
+                   bcl->stats.recv_fragmented,
+                   bcl->stats.recv_bundles,
+                   bcl->stats.recv_bundled);
+       tipc_printf(&pb, "  TX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+                   bcl->stats.sent_info,
+                   bcl->stats.sent_fragments,
+                   bcl->stats.sent_fragmented, 
+                   bcl->stats.sent_bundles,
+                   bcl->stats.sent_bundled);
+       tipc_printf(&pb, "  RX naks:%u defs:%u dups:%u\n", 
+                   bcl->stats.recv_nacks,
+                   bcl->stats.deferred_recv, 
+                   bcl->stats.duplicates);
+       tipc_printf(&pb, "  TX naks:%u acks:%u dups:%u\n", 
+                   bcl->stats.sent_nacks, 
+                   bcl->stats.sent_acks, 
+                   bcl->stats.retransmitted);
+       tipc_printf(&pb, "  Congestion bearer:%u link:%u  Send queue max:%u avg:%u\n",
+                   bcl->stats.bearer_congs,
+                   bcl->stats.link_congs,
+                   bcl->stats.max_queue_sz,
+                   bcl->stats.queue_sz_counts
+                   ? (bcl->stats.accu_queue_sz / bcl->stats.queue_sz_counts)
+                   : 0);
+
+       spin_unlock_bh(&bc_lock);
+       return printbuf_validate(&pb);
+}
+
+int bclink_reset_stats(void)
+{
+       if (!bcl)
+               return -ENOPROTOOPT;
+
+       spin_lock_bh(&bc_lock);
+       memset(&bcl->stats, 0, sizeof(bcl->stats));
+       spin_unlock_bh(&bc_lock);
+       return TIPC_OK;
+}
+
+int bclink_set_queue_limits(u32 limit)
+{
+       if (!bcl)
+               return -ENOPROTOOPT;
+       if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN))
+               return -EINVAL;
+
+       spin_lock_bh(&bc_lock);
+       link_set_queue_limits(bcl, limit);
+       spin_unlock_bh(&bc_lock);
+       return TIPC_OK;
+}
+
+int bclink_init(void)
+{
+       bcbearer = kmalloc(sizeof(*bcbearer), GFP_ATOMIC);
+       bclink = kmalloc(sizeof(*bclink), GFP_ATOMIC);
+       if (!bcbearer || !bclink) {
+ nomem:
+               warn("Memory squeeze; Failed to create multicast link\n");
+               kfree(bcbearer);
+               bcbearer = NULL;
+               kfree(bclink);
+               bclink = NULL;
+               return -ENOMEM;
+       }
+
+       memset(bcbearer, 0, sizeof(struct bcbearer));
+       INIT_LIST_HEAD(&bcbearer->bearer.cong_links);
+       bcbearer->bearer.media = &bcbearer->media;
+       bcbearer->media.send_msg = bcbearer_send;
+       sprintf(bcbearer->media.name, "tipc-multicast");
+
+       bcl = &bclink->link;
+       memset(bclink, 0, sizeof(struct bclink));
+       INIT_LIST_HEAD(&bcl->waiting_ports);
+       bcl->next_out_no = 1;
+       bclink->node.lock =  SPIN_LOCK_UNLOCKED;        
+       bcl->owner = &bclink->node;
+        bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
+       link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
+       bcl->b_ptr = &bcbearer->bearer;
+       bcl->state = WORKING_WORKING;
+       sprintf(bcl->name, bc_link_name);
+
+       if (BCLINK_LOG_BUF_SIZE) {
+               char *pb = kmalloc(BCLINK_LOG_BUF_SIZE, GFP_ATOMIC);
+
+               if (!pb)
+                       goto nomem;
+               printbuf_init(&bcl->print_buf, pb, BCLINK_LOG_BUF_SIZE);
+       }
+
+       return TIPC_OK;
+}
+
+void bclink_stop(void)
+{
+       spin_lock_bh(&bc_lock);
+       if (bcbearer) {
+               link_stop(bcl);
+               if (BCLINK_LOG_BUF_SIZE)
+                       kfree(bcl->print_buf.buf);
+               bcl = NULL;
+               kfree(bclink);
+               bclink = NULL;
+               kfree(bcbearer);
+               bcbearer = NULL;
+       }
+       spin_unlock_bh(&bc_lock);
+}
+
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
new file mode 100644 (file)
index 0000000..5430e52
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * net/tipc/bcast.h: Include file for TIPC broadcast code
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_BCAST_H
+#define _TIPC_BCAST_H
+
+#define MAX_NODES 4096
+#define WSIZE 32
+
+/**
+ * struct node_map - set of node identifiers
+ * @count: # of nodes in set
+ * @map: bitmap of node identifiers that are in the set
+ */
+
+struct node_map {
+       u32 count;
+       u32 map[MAX_NODES / WSIZE];
+};
+
+
+#define PLSIZE 32
+
+/**
+ * struct port_list - set of node local destination ports
+ * @count: # of ports in set (only valid for first entry in list)
+ * @next: pointer to next entry in list
+ * @ports: array of port references
+ */
+
+struct port_list {
+       int count;
+       struct port_list *next;
+       u32 ports[PLSIZE];
+};
+
+
+struct node;
+
+extern char bc_link_name[];
+
+
+/**
+ * nmap_get - determine if node exists in a node map
+ */
+
+static inline int nmap_get(struct node_map *nm_ptr, u32 node)
+{
+       int n = tipc_node(node);
+       int w = n / WSIZE;
+       int b = n % WSIZE;
+
+       return nm_ptr->map[w] & (1 << b);
+}
+
+/**
+ * nmap_add - add a node to a node map
+ */
+
+static inline void nmap_add(struct node_map *nm_ptr, u32 node)
+{
+       int n = tipc_node(node);
+       int w = n / WSIZE;
+       u32 mask = (1 << (n % WSIZE));
+
+       if ((nm_ptr->map[w] & mask) == 0) {
+               nm_ptr->count++;
+               nm_ptr->map[w] |= mask;
+       }
+}
+
+/** 
+ * nmap_remove - remove a node from a node map
+ */
+
+static inline void nmap_remove(struct node_map *nm_ptr, u32 node)
+{
+       int n = tipc_node(node);
+       int w = n / WSIZE;
+       u32 mask = (1 << (n % WSIZE));
+
+       if ((nm_ptr->map[w] & mask) != 0) {
+               nm_ptr->map[w] &= ~mask;
+               nm_ptr->count--;
+       }
+}
+
+/**
+ * nmap_equal - test for equality of node maps
+ */
+
+static inline int nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
+{
+       return !memcmp(nm_a, nm_b, sizeof(*nm_a));
+}
+
+/**
+ * nmap_diff - find differences between node maps
+ * @nm_a: input node map A
+ * @nm_b: input node map B
+ * @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
+ */
+
+static inline void nmap_diff(struct node_map *nm_a, struct node_map *nm_b,
+                            struct node_map *nm_diff)
+{
+       int stop = sizeof(nm_a->map) / sizeof(u32);
+       int w;
+       int b;
+       u32 map;
+
+       memset(nm_diff, 0, sizeof(*nm_diff));
+       for (w = 0; w < stop; w++) {
+               map = nm_a->map[w] ^ (nm_a->map[w] & nm_b->map[w]);
+               nm_diff->map[w] = map;
+               if (map != 0) {
+                       for (b = 0 ; b < WSIZE; b++) {
+                               if (map & (1 << b))
+                                       nm_diff->count++;
+                       }
+               }
+       }
+}
+
+/**
+ * port_list_add - add a port to a port list, ensuring no duplicates
+ */
+
+static inline void port_list_add(struct port_list *pl_ptr, u32 port)
+{
+       struct port_list *item = pl_ptr;
+       int i;
+       int item_sz = PLSIZE;
+       int cnt = pl_ptr->count;
+
+       for (; ; cnt -= item_sz, item = item->next) {
+               if (cnt < PLSIZE)
+                       item_sz = cnt;
+               for (i = 0; i < item_sz; i++)
+                       if (item->ports[i] == port)
+                               return;
+               if (i < PLSIZE) {
+                       item->ports[i] = port;
+                       pl_ptr->count++;
+                       return;
+               }
+               if (!item->next) {
+                       item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
+                       if (!item->next) {
+                               warn("Memory squeeze: multicast destination port list is incomplete\n");
+                               return;
+                       }
+                       item->next->next = NULL;
+               }
+       }
+}
+
+/**
+ * port_list_free - free dynamically created entries in port_list chain
+ * 
+ * Note: First item is on stack, so it doesn't need to be released
+ */
+
+static inline void port_list_free(struct port_list *pl_ptr)
+{
+       struct port_list *item;
+       struct port_list *next;
+
+       for (item = pl_ptr->next; item; item = next) {
+               next = item->next;
+               kfree(item);
+       }
+}
+
+
+int  bclink_init(void);
+void bclink_stop(void);
+void bclink_acknowledge(struct node *n_ptr, u32 acked);
+int  bclink_send_msg(struct sk_buff *buf);
+void bclink_recv_pkt(struct sk_buff *buf);
+u32  bclink_get_last_sent(void);
+u32  bclink_acks_missing(struct node *n_ptr);
+void bclink_check_gap(struct node *n_ptr, u32 seqno);
+int  bclink_stats(char *stats_buf, const u32 buf_size);
+int  bclink_reset_stats(void);
+int  bclink_set_queue_limits(u32 limit);
+void bcbearer_sort(void);
+void bcbearer_push(void);
+
+#endif
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
new file mode 100644 (file)
index 0000000..3dd19fd
--- /dev/null
@@ -0,0 +1,692 @@
+/*
+ * net/tipc/bearer.c: TIPC bearer code
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+#include "bearer.h"
+#include "link.h"
+#include "port.h"
+#include "discover.h"
+#include "bcast.h"
+
+#define MAX_ADDR_STR 32
+
+static struct media *media_list = 0;
+static u32 media_count = 0;
+
+struct bearer *bearers = 0;
+
+/**
+ * media_name_valid - validate media name
+ * 
+ * Returns 1 if media name is valid, otherwise 0.
+ */
+
+static int media_name_valid(const char *name)
+{
+       u32 len;
+
+       len = strlen(name);
+       if ((len + 1) > TIPC_MAX_MEDIA_NAME)
+               return 0;
+       return (strspn(name, tipc_alphabet) == len);
+}
+
+/**
+ * media_find - locates specified media object by name
+ */
+
+static struct media *media_find(const char *name)
+{
+       struct media *m_ptr;
+       u32 i;
+
+       for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+               if (!strcmp(m_ptr->name, name))
+                       return m_ptr;
+       }
+       return 0;
+}
+
+/**
+ * tipc_register_media - register a media type
+ * 
+ * Bearers for this media type must be activated separately at a later stage.
+ */
+
+int  tipc_register_media(u32 media_type,
+                        char *name, 
+                        int (*enable)(struct tipc_bearer *), 
+                        void (*disable)(struct tipc_bearer *), 
+                        int (*send_msg)(struct sk_buff *, 
+                                        struct tipc_bearer *,
+                                        struct tipc_media_addr *), 
+                        char *(*addr2str)(struct tipc_media_addr *a,
+                                          char *str_buf, int str_size),
+                        struct tipc_media_addr *bcast_addr,
+                        const u32 bearer_priority,
+                        const u32 link_tolerance,  /* [ms] */
+                        const u32 send_window_limit)
+{
+       struct media *m_ptr;
+       u32 media_id;
+       u32 i;
+       int res = -EINVAL;
+
+       write_lock_bh(&net_lock);
+       if (!media_list)
+               goto exit;
+
+       if (!media_name_valid(name)) {
+               warn("Media registration error: illegal name <%s>\n", name);
+               goto exit;
+       }
+       if (!bcast_addr) {
+               warn("Media registration error: no broadcast address supplied\n");
+               goto exit;
+       }
+       if (bearer_priority >= TIPC_NUM_LINK_PRI) {
+               warn("Media registration error: priority %u\n", bearer_priority);
+               goto exit;
+       }
+       if ((link_tolerance < TIPC_MIN_LINK_TOL) || 
+           (link_tolerance > TIPC_MAX_LINK_TOL)) {
+               warn("Media registration error: tolerance %u\n", link_tolerance);
+               goto exit;
+       }
+
+       media_id = media_count++;
+       if (media_id >= MAX_MEDIA) {
+               warn("Attempt to register more than %u media\n", MAX_MEDIA);
+               media_count--;
+               goto exit;
+       }
+       for (i = 0; i < media_id; i++) {
+               if (media_list[i].type_id == media_type) {
+                       warn("Attempt to register second media with type %u\n", 
+                            media_type);
+                       media_count--;
+                       goto exit;
+               }
+               if (!strcmp(name, media_list[i].name)) {
+                       warn("Attempt to re-register media name <%s>\n", name);
+                       media_count--;
+                       goto exit;
+               }
+       }
+
+       m_ptr = &media_list[media_id];
+       m_ptr->type_id = media_type;
+       m_ptr->send_msg = send_msg;
+       m_ptr->enable_bearer = enable;
+       m_ptr->disable_bearer = disable;
+       m_ptr->addr2str = addr2str;
+       memcpy(&m_ptr->bcast_addr, bcast_addr, sizeof(*bcast_addr));
+       m_ptr->bcast = 1;
+       strcpy(m_ptr->name, name);
+       m_ptr->priority = bearer_priority;
+       m_ptr->tolerance = link_tolerance;
+       m_ptr->window = send_window_limit;
+       dbg("Media <%s> registered\n", name);
+       res = 0;
+exit:
+       write_unlock_bh(&net_lock);
+       return res;
+}
+
+/**
+ * media_addr_printf - record media address in print buffer
+ */
+
+void media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
+{
+       struct media *m_ptr;
+       u32 media_type;
+       u32 i;
+
+       media_type = ntohl(a->type);
+       for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+               if (m_ptr->type_id == media_type)
+                       break;
+       }
+
+       if ((i < media_count) && (m_ptr->addr2str != NULL)) {
+               char addr_str[MAX_ADDR_STR];
+
+               tipc_printf(pb, "%s(%s) ", m_ptr->name, 
+                           m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
+       } else {
+               unchar *addr = (unchar *)&a->dev_addr;
+
+               tipc_printf(pb, "UNKNOWN(%u):", media_type);
+               for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
+                       tipc_printf(pb, "%02x ", addr[i]);
+               }
+       }
+}
+
+/**
+ * media_get_names - record names of registered media in buffer
+ */
+
+struct sk_buff *media_get_names(void)
+{
+       struct sk_buff *buf;
+       struct media *m_ptr;
+       int i;
+
+       buf = cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
+       if (!buf)
+               return NULL;
+
+       read_lock_bh(&net_lock);
+       for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+               cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, m_ptr->name, 
+                              strlen(m_ptr->name) + 1);
+       }
+       read_unlock_bh(&net_lock);
+       return buf;
+}
+
+/**
+ * bearer_name_validate - validate & (optionally) deconstruct bearer name
+ * @name - ptr to bearer name string
+ * @name_parts - ptr to area for bearer name components (or NULL if not needed)
+ * 
+ * Returns 1 if bearer name is valid, otherwise 0.
+ */
+
+static int bearer_name_validate(const char *name, 
+                               struct bearer_name *name_parts)
+{
+       char name_copy[TIPC_MAX_BEARER_NAME];
+       char *media_name;
+       char *if_name;
+       u32 media_len;
+       u32 if_len;
+
+       /* copy bearer name & ensure length is OK */
+
+       name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
+       /* need above in case non-Posix strncpy() doesn't pad with nulls */
+       strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
+       if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
+               return 0;
+
+       /* ensure all component parts of bearer name are present */
+
+       media_name = name_copy;
+       if ((if_name = strchr(media_name, ':')) == NULL)
+               return 0;
+       *(if_name++) = 0;
+       media_len = if_name - media_name;
+       if_len = strlen(if_name) + 1;
+
+       /* validate component parts of bearer name */
+
+       if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) || 
+           (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME) || 
+           (strspn(media_name, tipc_alphabet) != (media_len - 1)) ||
+           (strspn(if_name, tipc_alphabet) != (if_len - 1)))
+               return 0;
+
+       /* return bearer name components, if necessary */
+
+       if (name_parts) {
+               strcpy(name_parts->media_name, media_name);
+               strcpy(name_parts->if_name, if_name);
+       }
+       return 1;
+}
+
+/**
+ * bearer_find - locates bearer object with matching bearer name
+ */
+
+static struct bearer *bearer_find(const char *name)
+{
+       struct bearer *b_ptr;
+       u32 i;
+
+       for (i = 0, b_ptr = bearers; i < MAX_BEARERS; i++, b_ptr++) {
+               if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
+                       return b_ptr;
+       }
+       return 0;
+}
+
+/**
+ * bearer_find - locates bearer object with matching interface name
+ */
+
+struct bearer *bearer_find_interface(const char *if_name)
+{
+       struct bearer *b_ptr;
+       char *b_if_name;
+       u32 i;
+
+       for (i = 0, b_ptr = bearers; i < MAX_BEARERS; i++, b_ptr++) {
+               if (!b_ptr->active)
+                       continue;
+               b_if_name = strchr(b_ptr->publ.name, ':') + 1;
+               if (!strcmp(b_if_name, if_name))
+                       return b_ptr;
+       }
+       return 0;
+}
+
+/**
+ * bearer_get_names - record names of bearers in buffer
+ */
+
+struct sk_buff *bearer_get_names(void)
+{
+       struct sk_buff *buf;
+       struct media *m_ptr;
+       struct bearer *b_ptr;
+       int i, j;
+
+       buf = cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
+       if (!buf)
+               return NULL;
+
+       read_lock_bh(&net_lock);
+       for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
+               for (j = 0; j < MAX_BEARERS; j++) {
+                       b_ptr = &bearers[j];
+                       if (b_ptr->active && (b_ptr->media == m_ptr)) {
+                               cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME, 
+                                              b_ptr->publ.name, 
+                                              strlen(b_ptr->publ.name) + 1);
+                       }
+               }
+       }
+       read_unlock_bh(&net_lock);
+       return buf;
+}
+
+void bearer_add_dest(struct bearer *b_ptr, u32 dest)
+{
+       nmap_add(&b_ptr->nodes, dest);
+       disc_update_link_req(b_ptr->link_req);
+       bcbearer_sort();
+}
+
+void bearer_remove_dest(struct bearer *b_ptr, u32 dest)
+{
+       nmap_remove(&b_ptr->nodes, dest);
+       disc_update_link_req(b_ptr->link_req);
+       bcbearer_sort();
+}
+
+/*
+ * bearer_push(): Resolve bearer congestion. Force the waiting
+ * links to push out their unsent packets, one packet per link
+ * per iteration, until all packets are gone or congestion reoccurs.
+ * 'net_lock' is read_locked when this function is called
+ * bearer.lock must be taken before calling
+ * Returns binary true(1) ore false(0)
+ */
+static int bearer_push(struct bearer *b_ptr)
+{
+       u32 res = TIPC_OK;
+       struct link *ln, *tln;
+
+       if (b_ptr->publ.blocked)
+               return 0;
+
+       while (!list_empty(&b_ptr->cong_links) && (res != PUSH_FAILED)) {
+               list_for_each_entry_safe(ln, tln, &b_ptr->cong_links, link_list) {
+                       res = link_push_packet(ln);
+                       if (res == PUSH_FAILED)
+                               break;
+                       if (res == PUSH_FINISHED)
+                               list_move_tail(&ln->link_list, &b_ptr->links);
+               }
+       }
+       return list_empty(&b_ptr->cong_links);
+}
+
+void bearer_lock_push(struct bearer *b_ptr)
+{
+       int res;
+
+       spin_lock_bh(&b_ptr->publ.lock);
+       res = bearer_push(b_ptr);
+       spin_unlock_bh(&b_ptr->publ.lock);
+       if (res)
+               bcbearer_push();
+}
+
+
+/*
+ * Interrupt enabling new requests after bearer congestion or blocking:    
+ * See bearer_send().   
+ */
+void tipc_continue(struct tipc_bearer *tb_ptr)
+{
+       struct bearer *b_ptr = (struct bearer *)tb_ptr;
+
+       spin_lock_bh(&b_ptr->publ.lock);
+       b_ptr->continue_count++;
+       if (!list_empty(&b_ptr->cong_links))
+               k_signal((Handler)bearer_lock_push, (unsigned long)b_ptr);
+       b_ptr->publ.blocked = 0;
+       spin_unlock_bh(&b_ptr->publ.lock);
+}
+
+/*
+ * Schedule link for sending of messages after the bearer 
+ * has been deblocked by 'continue()'. This method is called 
+ * when somebody tries to send a message via this link while 
+ * the bearer is congested. 'net_lock' is in read_lock here
+ * bearer.lock is busy
+ */
+
+static void bearer_schedule_unlocked(struct bearer *b_ptr, struct link *l_ptr)
+{
+       list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
+}
+
+/*
+ * Schedule link for sending of messages after the bearer 
+ * has been deblocked by 'continue()'. This method is called 
+ * when somebody tries to send a message via this link while 
+ * the bearer is congested. 'net_lock' is in read_lock here,
+ * bearer.lock is free
+ */
+
+void bearer_schedule(struct bearer *b_ptr, struct link *l_ptr)
+{
+       spin_lock_bh(&b_ptr->publ.lock);
+       bearer_schedule_unlocked(b_ptr, l_ptr);
+       spin_unlock_bh(&b_ptr->publ.lock);
+}
+
+
+/*
+ * bearer_resolve_congestion(): Check if there is bearer congestion,
+ * and if there is, try to resolve it before returning.
+ * 'net_lock' is read_locked when this function is called
+ */
+int bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr)
+{
+       int res = 1;
+
+       if (list_empty(&b_ptr->cong_links))
+               return 1;
+       spin_lock_bh(&b_ptr->publ.lock);
+       if (!bearer_push(b_ptr)) {
+               bearer_schedule_unlocked(b_ptr, l_ptr);
+               res = 0;
+       }
+       spin_unlock_bh(&b_ptr->publ.lock);
+       return res;
+}
+
+
+/**
+ * tipc_enable_bearer - enable bearer with the given name
+ */              
+
+int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
+{
+       struct bearer *b_ptr;
+       struct media *m_ptr;
+       struct bearer_name b_name;
+       char addr_string[16];
+       u32 bearer_id;
+       u32 with_this_prio;
+       u32 i;
+       int res = -EINVAL;
+
+       if (tipc_mode != TIPC_NET_MODE)
+               return -ENOPROTOOPT;
+       if (!bearer_name_validate(name, &b_name) ||
+           !addr_domain_valid(bcast_scope) ||
+           !in_scope(bcast_scope, tipc_own_addr) ||
+           (priority > TIPC_NUM_LINK_PRI))
+               return -EINVAL;
+
+       write_lock_bh(&net_lock);
+       if (!bearers)
+               goto failed;
+
+       m_ptr = media_find(b_name.media_name);
+       if (!m_ptr) {
+               warn("No media <%s>\n", b_name.media_name);
+               goto failed;
+       }
+       if (priority == TIPC_NUM_LINK_PRI)
+               priority = m_ptr->priority;
+
+restart:
+       bearer_id = MAX_BEARERS;
+       with_this_prio = 1;
+       for (i = MAX_BEARERS; i-- != 0; ) {
+               if (!bearers[i].active) {
+                       bearer_id = i;
+                       continue;
+               }
+               if (!strcmp(name, bearers[i].publ.name)) {
+                       warn("Bearer <%s> already enabled\n", name);
+                       goto failed;
+               }
+               if ((bearers[i].priority == priority) &&
+                   (++with_this_prio > 2)) {
+                       if (priority-- == 0) {
+                               warn("Third bearer <%s> with priority %u, unable to lower to %u\n",
+                                    name, priority + 1, priority);
+                               goto failed;
+                       }
+                       warn("Third bearer <%s> with priority %u, lowering to %u\n",
+                            name, priority + 1, priority);
+                       goto restart;
+               }
+       }
+       if (bearer_id >= MAX_BEARERS) {
+               warn("Attempt to enable more than %d bearers\n", MAX_BEARERS);
+               goto failed;
+       }
+
+       b_ptr = &bearers[bearer_id];
+       memset(b_ptr, 0, sizeof(struct bearer));
+
+       strcpy(b_ptr->publ.name, name);
+       res = m_ptr->enable_bearer(&b_ptr->publ);
+       if (res) {
+               warn("Failed to enable bearer <%s>\n", name);
+               goto failed;
+       }
+
+       b_ptr->identity = bearer_id;
+       b_ptr->media = m_ptr;
+       b_ptr->net_plane = bearer_id + 'A';
+       b_ptr->active = 1;
+       b_ptr->detect_scope = bcast_scope;
+       b_ptr->priority = priority;
+       INIT_LIST_HEAD(&b_ptr->cong_links);
+       INIT_LIST_HEAD(&b_ptr->links);
+       if (m_ptr->bcast) {
+               b_ptr->link_req = disc_init_link_req(b_ptr, &m_ptr->bcast_addr,
+                                                    bcast_scope, 2);
+       }
+       b_ptr->publ.lock = SPIN_LOCK_UNLOCKED;
+       write_unlock_bh(&net_lock);
+       info("Enabled bearer <%s>, discovery domain %s\n",
+            name, addr_string_fill(addr_string, bcast_scope));
+       return 0;
+failed:
+       write_unlock_bh(&net_lock);
+       return res;
+}
+
+/**
+ * tipc_block_bearer(): Block the bearer with the given name,
+ *                      and reset all its links
+ */
+
+int tipc_block_bearer(const char *name)
+{
+       struct bearer *b_ptr = 0;
+       struct link *l_ptr;
+       struct link *temp_l_ptr;
+
+       if (tipc_mode != TIPC_NET_MODE)
+               return -ENOPROTOOPT;
+
+       read_lock_bh(&net_lock);
+       b_ptr = bearer_find(name);
+       if (!b_ptr) {
+               warn("Attempt to block unknown bearer <%s>\n", name);
+               read_unlock_bh(&net_lock);
+               return -EINVAL;
+       }
+
+       spin_lock_bh(&b_ptr->publ.lock);
+       b_ptr->publ.blocked = 1;
+       list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
+               struct node *n_ptr = l_ptr->owner;
+
+               spin_lock_bh(&n_ptr->lock);
+               link_reset(l_ptr);
+               spin_unlock_bh(&n_ptr->lock);
+       }
+       spin_unlock_bh(&b_ptr->publ.lock);
+       read_unlock_bh(&net_lock);
+       info("Blocked bearer <%s>\n", name);
+       return TIPC_OK;
+}
+
+/**
+ * bearer_disable -
+ * 
+ * Note: This routine assumes caller holds net_lock.
+ */
+
+static int bearer_disable(const char *name)
+{
+       struct bearer *b_ptr;
+       struct link *l_ptr;
+       struct link *temp_l_ptr;
+
+       if (tipc_mode != TIPC_NET_MODE)
+               return -ENOPROTOOPT;
+
+       b_ptr = bearer_find(name);
+       if (!b_ptr) {
+               warn("Attempt to disable unknown bearer <%s>\n", name);
+               return -EINVAL;
+       }
+
+       disc_stop_link_req(b_ptr->link_req);
+       spin_lock_bh(&b_ptr->publ.lock);
+       b_ptr->link_req = NULL;
+       b_ptr->publ.blocked = 1;
+       if (b_ptr->media->disable_bearer) {
+               spin_unlock_bh(&b_ptr->publ.lock);
+               write_unlock_bh(&net_lock);
+               b_ptr->media->disable_bearer(&b_ptr->publ);
+               write_lock_bh(&net_lock);
+               spin_lock_bh(&b_ptr->publ.lock);
+       }
+       list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
+               link_delete(l_ptr);
+       }
+       spin_unlock_bh(&b_ptr->publ.lock);
+       info("Disabled bearer <%s>\n", name);
+       memset(b_ptr, 0, sizeof(struct bearer));
+       return TIPC_OK;
+}
+
+int tipc_disable_bearer(const char *name)
+{
+       int res;
+
+       write_lock_bh(&net_lock);
+       res = bearer_disable(name);
+       write_unlock_bh(&net_lock);
+       return res;
+}
+
+
+
+int bearer_init(void)
+{
+       int res;
+
+       write_lock_bh(&net_lock);
+       bearers = kmalloc(MAX_BEARERS * sizeof(struct bearer), GFP_ATOMIC);
+       media_list = kmalloc(MAX_MEDIA * sizeof(struct media), GFP_ATOMIC);
+       if (bearers && media_list) {
+               memset(bearers, 0, MAX_BEARERS * sizeof(struct bearer));
+               memset(media_list, 0, MAX_MEDIA * sizeof(struct media));
+               res = TIPC_OK;
+       } else {
+               kfree(bearers);
+               kfree(media_list);
+               bearers = 0;
+               media_list = 0;
+               res = -ENOMEM;
+       }
+       write_unlock_bh(&net_lock);
+       return res;
+}
+
+void bearer_stop(void)
+{
+       u32 i;
+
+       if (!bearers)
+               return;
+
+       for (i = 0; i < MAX_BEARERS; i++) {
+               if (bearers[i].active)
+                       bearers[i].publ.blocked = 1;
+       }
+       for (i = 0; i < MAX_BEARERS; i++) {
+               if (bearers[i].active)
+                       bearer_disable(bearers[i].publ.name);
+       }
+       kfree(bearers);
+       kfree(media_list);
+       bearers = 0;
+       media_list = 0;
+       media_count = 0;
+}
+
+
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
new file mode 100644 (file)
index 0000000..21e63d3
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * net/tipc/bearer.h: Include file for TIPC bearer code
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_BEARER_H
+#define _TIPC_BEARER_H
+
+#include <net/tipc/tipc_bearer.h>
+#include "bcast.h"
+
+#define MAX_BEARERS 8
+#define MAX_MEDIA 4
+
+
+/**
+ * struct media - TIPC media information available to internal users
+ * @send_msg: routine which handles buffer transmission
+ * @enable_bearer: routine which enables a bearer
+ * @disable_bearer: routine which disables a bearer
+ * @addr2str: routine which converts bearer's address to string form
+ * @bcast_addr: media address used in broadcasting
+ * @bcast: non-zero if media supports broadcasting [currently mandatory]
+ * @priority: default link (and bearer) priority
+ * @tolerance: default time (in ms) before declaring link failure
+ * @window: default window (in packets) before declaring link congestion
+ * @type_id: TIPC media identifier [defined in tipc_bearer.h]
+ * @name: media name
+ */
+struct media {
+       int (*send_msg)(struct sk_buff *buf, 
+                       struct tipc_bearer *b_ptr,
+                       struct tipc_media_addr *dest);
+       int (*enable_bearer)(struct tipc_bearer *b_ptr);
+       void (*disable_bearer)(struct tipc_bearer *b_ptr);
+       char *(*addr2str)(struct tipc_media_addr *a, 
+                         char *str_buf, int str_size);
+       struct tipc_media_addr bcast_addr;
+       int bcast;
+       u32 priority;
+       u32 tolerance;
+       u32 window;
+       u32 type_id;
+       char name[TIPC_MAX_MEDIA_NAME];
+};
+
+/**
+ * struct bearer - TIPC bearer information available to internal users
+ * @publ: bearer information available to privileged users
+ * @media: ptr to media structure associated with bearer
+ * @priority: default link priority for bearer
+ * @detect_scope: network address mask used during automatic link creation
+ * @identity: array index of this bearer within TIPC bearer array
+ * @link_req: ptr to (optional) structure making periodic link setup requests
+ * @links: list of non-congested links associated with bearer
+ * @cong_links: list of congested links associated with bearer
+ * @continue_count: # of times bearer has resumed after congestion or blocking
+ * @active: non-zero if bearer structure is represents a bearer
+ * @net_plane: network plane ('A' through 'H') currently associated with bearer
+ * @nodes: indicates which nodes in cluster can be reached through bearer
+ */
+struct bearer {
+       struct tipc_bearer publ;
+       struct media *media;
+       u32 priority;
+       u32 detect_scope;
+       u32 identity;
+       struct link_req *link_req;
+       struct list_head links;
+       struct list_head cong_links;
+       u32 continue_count;
+       int active;
+       char net_plane;
+       struct node_map nodes;
+};
+
+struct bearer_name {
+       char media_name[TIPC_MAX_MEDIA_NAME];
+       char if_name[TIPC_MAX_IF_NAME];
+};
+
+struct link;
+
+extern struct bearer *bearers;
+
+void media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a);
+struct sk_buff *media_get_names(void);
+
+struct sk_buff *bearer_get_names(void);
+void bearer_add_dest(struct bearer *b_ptr, u32 dest);
+void bearer_remove_dest(struct bearer *b_ptr, u32 dest);
+void bearer_schedule(struct bearer *b_ptr, struct link *l_ptr);
+struct bearer *bearer_find_interface(const char *if_name);
+int bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr);
+int bearer_init(void);
+void bearer_stop(void);
+int bearer_broadcast(struct sk_buff *buf, struct tipc_bearer *b_ptr,
+                    struct tipc_media_addr *dest);
+void bearer_lock_push(struct bearer *b_ptr);
+
+
+/**
+ * bearer_send- sends buffer to destination over bearer 
+ * 
+ * Returns true (1) if successful, or false (0) if unable to send
+ * 
+ * IMPORTANT:
+ * The media send routine must not alter the buffer being passed in
+ * as it may be needed for later retransmission!
+ * 
+ * If the media send routine returns a non-zero value (indicating that 
+ * it was unable to send the buffer), it must:
+ *   1) mark the bearer as blocked,
+ *   2) call tipc_continue() once the bearer is able to send again.
+ * Media types that are unable to meet these two critera must ensure their
+ * send routine always returns success -- even if the buffer was not sent --
+ * and let TIPC's link code deal with the undelivered message. 
+ */
+
+static inline int bearer_send(struct bearer *b_ptr, struct sk_buff *buf,
+                             struct tipc_media_addr *dest)
+{
+       return !b_ptr->media->send_msg(buf, &b_ptr->publ, dest);
+}
+
+/**
+ * bearer_congested - determines if bearer is currently congested
+ */
+
+static inline int bearer_congested(struct bearer *b_ptr, struct link *l_ptr)
+{
+       if (unlikely(b_ptr->publ.blocked))
+               return 1;
+       if (likely(list_empty(&b_ptr->cong_links)))
+               return 0;
+       return !bearer_resolve_congestion(b_ptr, l_ptr);
+}
+
+#endif
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
new file mode 100644 (file)
index 0000000..f0f7bac
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * net/tipc/cluster.c: TIPC cluster management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "cluster.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "link.h"
+#include "node.h"
+#include "net.h"
+#include "msg.h"
+#include "bearer.h"
+
+void cluster_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
+                      u32 lower, u32 upper);
+struct sk_buff *cluster_prepare_routing_msg(u32 data_size, u32 dest);
+
+struct node **local_nodes = 0;
+struct node_map cluster_bcast_nodes = {0,{0,}};
+u32 highest_allowed_slave = 0;
+
+struct cluster *cluster_create(u32 addr)
+{
+       struct _zone *z_ptr;
+       struct cluster *c_ptr;
+       int max_nodes; 
+       int alloc;
+
+       c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC);
+       if (c_ptr == NULL)
+               return 0;
+       memset(c_ptr, 0, sizeof(*c_ptr));
+
+       c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
+       if (in_own_cluster(addr))
+               max_nodes = LOWEST_SLAVE + tipc_max_slaves;
+       else
+               max_nodes = tipc_max_nodes + 1;
+       alloc = sizeof(void *) * (max_nodes + 1);
+       c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC);
+       if (c_ptr->nodes == NULL) {
+               kfree(c_ptr);
+               return 0;
+       }
+       memset(c_ptr->nodes, 0, alloc);  
+       if (in_own_cluster(addr))
+               local_nodes = c_ptr->nodes;
+       c_ptr->highest_slave = LOWEST_SLAVE - 1;
+       c_ptr->highest_node = 0;
+       
+       z_ptr = zone_find(tipc_zone(addr));
+       if (z_ptr == NULL) {
+               z_ptr = zone_create(addr);
+       }
+       if (z_ptr != NULL) {
+               zone_attach_cluster(z_ptr, c_ptr);
+               c_ptr->owner = z_ptr;
+       }
+       else {
+               kfree(c_ptr);
+               c_ptr = 0;
+       }
+
+       return c_ptr;
+}
+
+void cluster_delete(struct cluster *c_ptr)
+{
+       u32 n_num;
+
+       if (!c_ptr)
+               return;
+       for (n_num = 1; n_num <= c_ptr->highest_node; n_num++) {
+               node_delete(c_ptr->nodes[n_num]);
+       }
+       for (n_num = LOWEST_SLAVE; n_num <= c_ptr->highest_slave; n_num++) {
+               node_delete(c_ptr->nodes[n_num]);
+       }
+       kfree(c_ptr->nodes);
+       kfree(c_ptr);
+}
+
+u32 cluster_next_node(struct cluster *c_ptr, u32 addr)
+{
+       struct node *n_ptr;
+       u32 n_num = tipc_node(addr) + 1;
+
+       if (!c_ptr)
+               return addr;
+       for (; n_num <= c_ptr->highest_node; n_num++) {
+               n_ptr = c_ptr->nodes[n_num];
+               if (n_ptr && node_has_active_links(n_ptr))
+                       return n_ptr->addr;
+       }
+       for (n_num = 1; n_num < tipc_node(addr); n_num++) {
+               n_ptr = c_ptr->nodes[n_num];
+               if (n_ptr && node_has_active_links(n_ptr))
+                       return n_ptr->addr;
+       }
+       return 0;
+}
+
+void cluster_attach_node(struct cluster *c_ptr, struct node *n_ptr)
+{
+       u32 n_num = tipc_node(n_ptr->addr);
+       u32 max_n_num = tipc_max_nodes;
+
+       if (in_own_cluster(n_ptr->addr))
+               max_n_num = highest_allowed_slave;
+       assert(n_num > 0);
+       assert(n_num <= max_n_num);
+       assert(c_ptr->nodes[n_num] == 0);
+       c_ptr->nodes[n_num] = n_ptr;
+       if (n_num > c_ptr->highest_node)
+               c_ptr->highest_node = n_num;
+}
+
+/**
+ * cluster_select_router - select router to a cluster
+ * 
+ * Uses deterministic and fair algorithm.
+ */
+
+u32 cluster_select_router(struct cluster *c_ptr, u32 ref)
+{
+       u32 n_num;
+       u32 ulim = c_ptr->highest_node;
+       u32 mask;
+       u32 tstart;
+
+       assert(!in_own_cluster(c_ptr->addr));
+       if (!ulim)
+               return 0;
+
+       /* Start entry must be random */
+       mask = tipc_max_nodes;
+       while (mask > ulim)
+               mask >>= 1;
+       tstart = ref & mask;
+       n_num = tstart;
+
+       /* Lookup upwards with wrap-around */
+       do {
+               if (node_is_up(c_ptr->nodes[n_num]))
+                       break;
+       } while (++n_num <= ulim);
+       if (n_num > ulim) {
+               n_num = 1;
+               do {
+                       if (node_is_up(c_ptr->nodes[n_num]))
+                               break;
+               } while (++n_num < tstart);
+               if (n_num == tstart)
+                       return 0;
+       }
+       assert(n_num <= ulim);
+       return node_select_router(c_ptr->nodes[n_num], ref);
+}
+
+/**
+ * cluster_select_node - select destination node within a remote cluster
+ * 
+ * Uses deterministic and fair algorithm.
+ */
+
+struct node *cluster_select_node(struct cluster *c_ptr, u32 selector)
+{
+       u32 n_num;
+       u32 mask = tipc_max_nodes;
+       u32 start_entry;
+
+       assert(!in_own_cluster(c_ptr->addr));
+       if (!c_ptr->highest_node)
+               return 0;
+
+       /* Start entry must be random */
+       while (mask > c_ptr->highest_node) {
+               mask >>= 1;
+       }
+       start_entry = (selector & mask) ? selector & mask : 1u;
+       assert(start_entry <= c_ptr->highest_node);
+
+       /* Lookup upwards with wrap-around */
+       for (n_num = start_entry; n_num <= c_ptr->highest_node; n_num++) {
+               if (node_has_active_links(c_ptr->nodes[n_num]))
+                       return c_ptr->nodes[n_num];
+       }
+       for (n_num = 1; n_num < start_entry; n_num++) {
+               if (node_has_active_links(c_ptr->nodes[n_num]))
+                       return c_ptr->nodes[n_num];
+       }
+       return 0;
+}
+
+/*
+ *    Routing table management: See description in node.c
+ */
+
+struct sk_buff *cluster_prepare_routing_msg(u32 data_size, u32 dest)
+{
+       u32 size = INT_H_SIZE + data_size;
+       struct sk_buff *buf = buf_acquire(size);
+       struct tipc_msg *msg;
+
+       if (buf) {
+               msg = buf_msg(buf);
+               memset((char *)msg, 0, size);
+               msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest);
+       }
+       return buf;
+}
+
+void cluster_bcast_new_route(struct cluster *c_ptr, u32 dest,
+                            u32 lower, u32 upper)
+{
+       struct sk_buff *buf = cluster_prepare_routing_msg(0, c_ptr->addr);
+       struct tipc_msg *msg;
+
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_set_remote_node(msg, dest);
+               msg_set_type(msg, ROUTE_ADDITION);
+               cluster_multicast(c_ptr, buf, lower, upper);
+       } else {
+               warn("Memory squeeze: broadcast of new route failed\n");
+       }
+}
+
+void cluster_bcast_lost_route(struct cluster *c_ptr, u32 dest,
+                             u32 lower, u32 upper)
+{
+       struct sk_buff *buf = cluster_prepare_routing_msg(0, c_ptr->addr);
+       struct tipc_msg *msg;
+
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_set_remote_node(msg, dest);
+               msg_set_type(msg, ROUTE_REMOVAL);
+               cluster_multicast(c_ptr, buf, lower, upper);
+       } else {
+               warn("Memory squeeze: broadcast of lost route failed\n");
+       }
+}
+
+void cluster_send_slave_routes(struct cluster *c_ptr, u32 dest)
+{
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+       u32 highest = c_ptr->highest_slave;
+       u32 n_num;
+       int send = 0;
+
+       assert(!is_slave(dest));
+       assert(in_own_cluster(dest));
+       assert(in_own_cluster(c_ptr->addr));
+       if (highest <= LOWEST_SLAVE)
+               return;
+       buf = cluster_prepare_routing_msg(highest - LOWEST_SLAVE + 1,
+                                         c_ptr->addr);
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_set_remote_node(msg, c_ptr->addr);
+               msg_set_type(msg, SLAVE_ROUTING_TABLE);
+               for (n_num = LOWEST_SLAVE; n_num <= highest; n_num++) {
+                       if (c_ptr->nodes[n_num] && 
+                           node_has_active_links(c_ptr->nodes[n_num])) {
+                               send = 1;
+                               msg_set_dataoctet(msg, n_num);
+                       }
+               }
+               if (send)
+                       link_send(buf, dest, dest);
+               else
+                       buf_discard(buf);
+       } else {
+               warn("Memory squeeze: broadcast of lost route failed\n");
+       }
+}
+
+void cluster_send_ext_routes(struct cluster *c_ptr, u32 dest)
+{
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+       u32 highest = c_ptr->highest_node;
+       u32 n_num;
+       int send = 0;
+
+       if (in_own_cluster(c_ptr->addr))
+               return;
+       assert(!is_slave(dest));
+       assert(in_own_cluster(dest));
+       highest = c_ptr->highest_node;
+       buf = cluster_prepare_routing_msg(highest + 1, c_ptr->addr);
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_set_remote_node(msg, c_ptr->addr);
+               msg_set_type(msg, EXT_ROUTING_TABLE);
+               for (n_num = 1; n_num <= highest; n_num++) {
+                       if (c_ptr->nodes[n_num] && 
+                           node_has_active_links(c_ptr->nodes[n_num])) {
+                               send = 1;
+                               msg_set_dataoctet(msg, n_num);
+                       }
+               }
+               if (send)
+                       link_send(buf, dest, dest);
+               else
+                       buf_discard(buf);
+       } else {
+               warn("Memory squeeze: broadcast of external route failed\n");
+       }
+}
+
+void cluster_send_local_routes(struct cluster *c_ptr, u32 dest)
+{
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+       u32 highest = c_ptr->highest_node;
+       u32 n_num;
+       int send = 0;
+
+       assert(is_slave(dest));
+       assert(in_own_cluster(c_ptr->addr));
+       buf = cluster_prepare_routing_msg(highest, c_ptr->addr);
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_set_remote_node(msg, c_ptr->addr);
+               msg_set_type(msg, LOCAL_ROUTING_TABLE);
+               for (n_num = 1; n_num <= highest; n_num++) {
+                       if (c_ptr->nodes[n_num] && 
+                           node_has_active_links(c_ptr->nodes[n_num])) {
+                               send = 1;
+                               msg_set_dataoctet(msg, n_num);
+                       }
+               }
+               if (send)
+                       link_send(buf, dest, dest);
+               else
+                       buf_discard(buf);
+       } else {
+               warn("Memory squeeze: broadcast of local route failed\n");
+       }
+}
+
+void cluster_recv_routing_table(struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       struct cluster *c_ptr;
+       struct node *n_ptr;
+       unchar *node_table;
+       u32 table_size;
+       u32 router;
+       u32 rem_node = msg_remote_node(msg);
+       u32 z_num;
+       u32 c_num;
+       u32 n_num;
+
+       c_ptr = cluster_find(rem_node);
+       if (!c_ptr) {
+               c_ptr = cluster_create(rem_node);
+               if (!c_ptr) {
+                       buf_discard(buf);
+                       return;
+               }
+       }
+
+       node_table = buf->data + msg_hdr_sz(msg);
+       table_size = msg_size(msg) - msg_hdr_sz(msg);
+       router = msg_prevnode(msg);
+       z_num = tipc_zone(rem_node);
+       c_num = tipc_cluster(rem_node);
+
+       switch (msg_type(msg)) {
+       case LOCAL_ROUTING_TABLE:
+               assert(is_slave(tipc_own_addr));
+       case EXT_ROUTING_TABLE:
+               for (n_num = 1; n_num < table_size; n_num++) {
+                       if (node_table[n_num]) {
+                               u32 addr = tipc_addr(z_num, c_num, n_num);
+                               n_ptr = c_ptr->nodes[n_num];
+                               if (!n_ptr) {
+                                       n_ptr = node_create(addr);
+                               }
+                               if (n_ptr)
+                                       node_add_router(n_ptr, router);
+                       }
+               }
+               break;
+       case SLAVE_ROUTING_TABLE:
+               assert(!is_slave(tipc_own_addr));
+               assert(in_own_cluster(c_ptr->addr));
+               for (n_num = 1; n_num < table_size; n_num++) {
+                       if (node_table[n_num]) {
+                               u32 slave_num = n_num + LOWEST_SLAVE;
+                               u32 addr = tipc_addr(z_num, c_num, slave_num);
+                               n_ptr = c_ptr->nodes[slave_num];
+                               if (!n_ptr) {
+                                       n_ptr = node_create(addr);
+                               }
+                               if (n_ptr)
+                                       node_add_router(n_ptr, router);
+                       }
+               }
+               break;
+       case ROUTE_ADDITION:
+               if (!is_slave(tipc_own_addr)) {
+                       assert(!in_own_cluster(c_ptr->addr)
+                              || is_slave(rem_node));
+               } else {
+                       assert(in_own_cluster(c_ptr->addr)
+                              && !is_slave(rem_node));
+               }
+               n_ptr = c_ptr->nodes[tipc_node(rem_node)];
+               if (!n_ptr)
+                       n_ptr = node_create(rem_node);
+               if (n_ptr)
+                       node_add_router(n_ptr, router);
+               break;
+       case ROUTE_REMOVAL:
+               if (!is_slave(tipc_own_addr)) {
+                       assert(!in_own_cluster(c_ptr->addr)
+                              || is_slave(rem_node));
+               } else {
+                       assert(in_own_cluster(c_ptr->addr)
+                              && !is_slave(rem_node));
+               }
+               n_ptr = c_ptr->nodes[tipc_node(rem_node)];
+               if (n_ptr)
+                       node_remove_router(n_ptr, router);
+               break;
+       default:
+               assert(!"Illegal routing manager message received\n");
+       }
+       buf_discard(buf);
+}
+
+void cluster_remove_as_router(struct cluster *c_ptr, u32 router)
+{
+       u32 start_entry;
+       u32 tstop;
+       u32 n_num;
+
+       if (is_slave(router))
+               return; /* Slave nodes can not be routers */
+
+       if (in_own_cluster(c_ptr->addr)) {
+               start_entry = LOWEST_SLAVE;
+               tstop = c_ptr->highest_slave;
+       } else {
+               start_entry = 1;
+               tstop = c_ptr->highest_node;
+       }
+
+       for (n_num = start_entry; n_num <= tstop; n_num++) {
+               if (c_ptr->nodes[n_num]) {
+                       node_remove_router(c_ptr->nodes[n_num], router);
+               }
+       }
+}
+
+/**
+ * cluster_multicast - multicast message to local nodes 
+ */
+
+void cluster_multicast(struct cluster *c_ptr, struct sk_buff *buf, 
+                      u32 lower, u32 upper)
+{
+       struct sk_buff *buf_copy;
+       struct node *n_ptr;
+       u32 n_num;
+       u32 tstop;
+
+       assert(lower <= upper);
+       assert(((lower >= 1) && (lower <= tipc_max_nodes)) ||
+              ((lower >= LOWEST_SLAVE) && (lower <= highest_allowed_slave)));
+       assert(((upper >= 1) && (upper <= tipc_max_nodes)) ||
+              ((upper >= LOWEST_SLAVE) && (upper <= highest_allowed_slave)));
+       assert(in_own_cluster(c_ptr->addr));
+
+       tstop = is_slave(upper) ? c_ptr->highest_slave : c_ptr->highest_node;
+       if (tstop > upper)
+               tstop = upper;
+       for (n_num = lower; n_num <= tstop; n_num++) {
+               n_ptr = c_ptr->nodes[n_num];
+               if (n_ptr && node_has_active_links(n_ptr)) {
+                       buf_copy = skb_copy(buf, GFP_ATOMIC);
+                       if (buf_copy == NULL)
+                               break;
+                       msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
+                       link_send(buf_copy, n_ptr->addr, n_ptr->addr);
+               }
+       }
+       buf_discard(buf);
+}
+
+/**
+ * cluster_broadcast - broadcast message to all nodes within cluster
+ */
+
+void cluster_broadcast(struct sk_buff *buf)
+{
+       struct sk_buff *buf_copy;
+       struct cluster *c_ptr;
+       struct node *n_ptr;
+       u32 n_num;
+       u32 tstart;
+       u32 tstop;
+       u32 node_type;
+
+       if (tipc_mode == TIPC_NET_MODE) {
+               c_ptr = cluster_find(tipc_own_addr);
+               assert(in_own_cluster(c_ptr->addr));    /* For now */
+
+               /* Send to standard nodes, then repeat loop sending to slaves */
+               tstart = 1;
+               tstop = c_ptr->highest_node;
+               for (node_type = 1; node_type <= 2; node_type++) {
+                       for (n_num = tstart; n_num <= tstop; n_num++) {
+                               n_ptr = c_ptr->nodes[n_num];
+                               if (n_ptr && node_has_active_links(n_ptr)) {
+                                       buf_copy = skb_copy(buf, GFP_ATOMIC);
+                                       if (buf_copy == NULL)
+                                               goto exit;
+                                       msg_set_destnode(buf_msg(buf_copy), 
+                                                        n_ptr->addr);
+                                       link_send(buf_copy, n_ptr->addr, 
+                                                 n_ptr->addr);
+                               }
+                       }
+                       tstart = LOWEST_SLAVE;
+                       tstop = c_ptr->highest_slave;
+               }
+       }
+exit:
+       buf_discard(buf);
+}
+
+int cluster_init(void)
+{
+       highest_allowed_slave = LOWEST_SLAVE + tipc_max_slaves;
+       return cluster_create(tipc_own_addr) ? TIPC_OK : -ENOMEM;
+}
+
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h
new file mode 100644 (file)
index 0000000..1ffb095
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * net/tipc/cluster.h: Include file for TIPC cluster management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_CLUSTER_H
+#define _TIPC_CLUSTER_H
+
+#include "addr.h"
+#include "zone.h"
+
+#define LOWEST_SLAVE  2048u
+
+/**
+ * struct cluster - TIPC cluster structure
+ * @addr: network address of cluster
+ * @owner: pointer to zone that cluster belongs to
+ * @nodes: array of pointers to all nodes within cluster
+ * @highest_node: id of highest numbered node within cluster
+ * @highest_slave: (used for secondary node support)
+ */
+struct cluster {
+       u32 addr;
+       struct _zone *owner;
+       struct node **nodes;
+       u32 highest_node;
+       u32 highest_slave;
+};
+
+
+extern struct node **local_nodes;
+extern u32 highest_allowed_slave;
+extern struct node_map cluster_bcast_nodes;
+
+void cluster_remove_as_router(struct cluster *c_ptr, u32 router);
+void cluster_send_ext_routes(struct cluster *c_ptr, u32 dest);
+struct node *cluster_select_node(struct cluster *c_ptr, u32 selector);
+u32 cluster_select_router(struct cluster *c_ptr, u32 ref);
+void cluster_recv_routing_table(struct sk_buff *buf);
+struct cluster *cluster_create(u32 addr);
+void cluster_delete(struct cluster *c_ptr);
+void cluster_attach_node(struct cluster *c_ptr, struct node *n_ptr);
+void cluster_send_slave_routes(struct cluster *c_ptr, u32 dest);
+void cluster_broadcast(struct sk_buff *buf);
+int cluster_init(void);
+u32 cluster_next_node(struct cluster *c_ptr, u32 addr);
+void cluster_bcast_new_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
+void cluster_send_local_routes(struct cluster *c_ptr, u32 dest);
+void cluster_bcast_lost_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
+
+static inline struct cluster *cluster_find(u32 addr)
+{
+       struct _zone *z_ptr = zone_find(addr);
+
+       if (z_ptr)
+               return z_ptr->clusters[1];
+       return 0;
+}
+
+#endif
diff --git a/net/tipc/config.c b/net/tipc/config.c
new file mode 100644 (file)
index 0000000..8ddef4f
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * net/tipc/config.c: TIPC configuration management code
+ * 
+ * Copyright (c) 2002-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "bearer.h"
+#include "port.h"
+#include "link.h"
+#include "zone.h"
+#include "addr.h"
+#include "name_table.h"
+#include "node.h"
+#include "config.h"
+#include "discover.h"
+
+struct subscr_data {
+       char usr_handle[8];
+       u32 domain;
+       u32 port_ref;
+       struct list_head subd_list;
+};
+
+struct manager {
+       u32 user_ref;
+       u32 port_ref;
+       u32 subscr_ref;
+       u32 link_subscriptions;
+       struct list_head link_subscribers;
+};
+
+static struct manager mng = { 0};
+
+static spinlock_t config_lock = SPIN_LOCK_UNLOCKED;
+
+static const void *req_tlv_area;       /* request message TLV area */
+static int req_tlv_space;              /* request message TLV area size */
+static int rep_headroom;               /* reply message headroom to use */
+
+
+void cfg_link_event(u32 addr, char *name, int up)
+{
+       /* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
+}
+
+
+struct sk_buff *cfg_reply_alloc(int payload_size)
+{
+       struct sk_buff *buf;
+
+       buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
+       if (buf)
+               skb_reserve(buf, rep_headroom);
+       return buf;
+}
+
+int cfg_append_tlv(struct sk_buff *buf, int tlv_type, 
+                  void *tlv_data, int tlv_data_size)
+{
+       struct tlv_desc *tlv = (struct tlv_desc *)buf->tail;
+       int new_tlv_space = TLV_SPACE(tlv_data_size);
+
+       if (skb_tailroom(buf) < new_tlv_space) {
+               dbg("cfg_append_tlv unable to append TLV\n");
+               return 0;
+       }
+       skb_put(buf, new_tlv_space);
+       tlv->tlv_type = htons(tlv_type);
+       tlv->tlv_len  = htons(TLV_LENGTH(tlv_data_size));
+       if (tlv_data_size && tlv_data)
+               memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
+       return 1;
+}
+
+struct sk_buff *cfg_reply_unsigned_type(u16 tlv_type, u32 value)
+{
+       struct sk_buff *buf;
+       u32 value_net;
+
+       buf = cfg_reply_alloc(TLV_SPACE(sizeof(value)));
+       if (buf) {
+               value_net = htonl(value);
+               cfg_append_tlv(buf, tlv_type, &value_net, 
+                              sizeof(value_net));
+       }
+       return buf;
+}
+
+struct sk_buff *cfg_reply_string_type(u16 tlv_type, char *string)
+{
+       struct sk_buff *buf;
+       int string_len = strlen(string) + 1;
+
+       buf = cfg_reply_alloc(TLV_SPACE(string_len));
+       if (buf)
+               cfg_append_tlv(buf, tlv_type, string, string_len);
+       return buf;
+}
+
+
+
+
+#if 0
+
+/* Now obsolete code for handling commands not yet implemented the new way */
+
+int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
+                char *data,
+                u32 sz,
+                u32 *ret_size,
+                struct tipc_portid *orig)
+{
+       int rv = -EINVAL;
+       u32 cmd = msg->cmd;
+
+       *ret_size = 0;
+       switch (cmd) {
+       case TIPC_REMOVE_LINK:
+       case TIPC_CMD_BLOCK_LINK:
+       case TIPC_CMD_UNBLOCK_LINK:
+               if (!cfg_check_connection(orig))
+                       rv = link_control(msg->argv.link_name, msg->cmd, 0);
+               break;
+       case TIPC_ESTABLISH:
+               {
+                       int connected;
+
+                       tipc_isconnected(mng.conn_port_ref, &connected);
+                       if (connected || !orig) {
+                               rv = TIPC_FAILURE;
+                               break;
+                       }
+                       rv = tipc_connect2port(mng.conn_port_ref, orig);
+                       if (rv == TIPC_OK)
+                               orig = 0;
+                       break;
+               }
+       case TIPC_GET_PEER_ADDRESS:
+               *ret_size = link_peer_addr(msg->argv.link_name, data, sz);
+               break;
+       case TIPC_GET_ROUTES:
+               rv = TIPC_OK;
+               break;
+       default: {}
+       }
+       if (*ret_size)
+               rv = TIPC_OK;
+       return rv;
+}
+
+static void cfg_cmd_event(struct tipc_cmd_msg *msg,
+                         char *data,
+                         u32 sz,        
+                         struct tipc_portid const *orig)
+{
+       int rv = -EINVAL;
+       struct tipc_cmd_result_msg rmsg;
+       struct iovec msg_sect[2];
+       int *arg;
+
+       msg->cmd = ntohl(msg->cmd);
+
+       cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect, 
+                           data, 0);
+       if (ntohl(msg->magic) != TIPC_MAGIC)
+               goto exit;
+
+       switch (msg->cmd) {
+       case TIPC_CREATE_LINK:
+               if (!cfg_check_connection(orig))
+                       rv = disc_create_link(&msg->argv.create_link);
+               break;
+       case TIPC_LINK_SUBSCRIBE:
+               {
+                       struct subscr_data *sub;
+
+                       if (mng.link_subscriptions > 64)
+                               break;
+                       sub = (struct subscr_data *)kmalloc(sizeof(*sub),
+                                                           GFP_ATOMIC);
+                       if (sub == NULL) {
+                               warn("Memory squeeze; dropped remote link subscription\n");
+                               break;
+                       }
+                       INIT_LIST_HEAD(&sub->subd_list);
+                       tipc_createport(mng.user_ref,
+                                       (void *)sub,
+                                       TIPC_HIGH_IMPORTANCE,
+                                       0,
+                                       0,
+                                       (tipc_conn_shutdown_event)cfg_linksubscr_cancel,
+                                       0,
+                                       0,
+                                       (tipc_conn_msg_event)cfg_linksubscr_cancel,
+                                       0,
+                                       &sub->port_ref);
+                       if (!sub->port_ref) {
+                               kfree(sub);
+                               break;
+                       }
+                       memcpy(sub->usr_handle,msg->usr_handle,
+                              sizeof(sub->usr_handle));
+                       sub->domain = msg->argv.domain;
+                       list_add_tail(&sub->subd_list, &mng.link_subscribers);
+                       tipc_connect2port(sub->port_ref, orig);
+                       rmsg.retval = TIPC_OK;
+                       tipc_send(sub->port_ref, 2u, msg_sect);
+                       mng.link_subscriptions++;
+                       return;
+               }
+       default:
+               rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
+       }
+       exit:
+       rmsg.result_len = htonl(msg_sect[1].iov_len);
+       rmsg.retval = htonl(rv);
+       cfg_respond(msg_sect, 2u, orig);
+}
+#endif
+
+static struct sk_buff *cfg_enable_bearer(void)
+{
+       struct tipc_bearer_config *args;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
+       if (tipc_enable_bearer(args->name,
+                              ntohl(args->detect_scope),
+                              ntohl(args->priority)))
+               return cfg_reply_error_string("unable to enable bearer");
+
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_disable_bearer(void)
+{
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
+               return cfg_reply_error_string("unable to disable bearer");
+
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_own_addr(void)
+{
+       u32 addr;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       addr = *(u32 *)TLV_DATA(req_tlv_area);
+       addr = ntohl(addr);
+       if (addr == tipc_own_addr)
+               return cfg_reply_none();
+       if (!addr_node_valid(addr))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (node address)");
+       if (tipc_own_addr)
+               return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                             " (cannot change node address once assigned)");
+
+       spin_unlock_bh(&config_lock);
+       stop_net();
+       tipc_own_addr = addr;
+       start_net();
+       spin_lock_bh(&config_lock);
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_remote_mng(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       tipc_remote_management = (value != 0);
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_publications(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 1, 65535))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (max publications must be 1-65535)");
+       tipc_max_publications = value;
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_subscriptions(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 1, 65535))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (max subscriptions must be 1-65535");
+       tipc_max_subscriptions = value;
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_ports(void)
+{
+       int orig_mode;
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 127, 65535))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (max ports must be 127-65535)");
+
+       if (value == tipc_max_ports)
+               return cfg_reply_none();
+
+       if (atomic_read(&tipc_user_count) > 2)
+               return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                             " (cannot change max ports while TIPC users exist)");
+
+       spin_unlock_bh(&config_lock);
+       orig_mode = tipc_get_mode();
+       if (orig_mode == TIPC_NET_MODE)
+               stop_net();
+       stop_core();
+       tipc_max_ports = value;
+       start_core();
+       if (orig_mode == TIPC_NET_MODE)
+               start_net();
+       spin_lock_bh(&config_lock);
+       return cfg_reply_none();
+}
+
+static struct sk_buff *set_net_max(int value, int *parameter)
+{
+       int orig_mode;
+
+       if (value != *parameter) {
+               orig_mode = tipc_get_mode();
+               if (orig_mode == TIPC_NET_MODE)
+                       stop_net();
+               *parameter = value;
+               if (orig_mode == TIPC_NET_MODE)
+                       start_net();
+       }
+
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_zones(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 1, 255))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (max zones must be 1-255)");
+       return set_net_max(value, &tipc_max_zones);
+}
+
+static struct sk_buff *cfg_set_max_clusters(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != 1)
+               return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                             " (max clusters fixed at 1)");
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_max_nodes(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 8, 2047))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (max nodes must be 8-2047)");
+       return set_net_max(value, &tipc_max_nodes);
+}
+
+static struct sk_buff *cfg_set_max_slaves(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != 0)
+               return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                             " (max secondary nodes fixed at 0)");
+       return cfg_reply_none();
+}
+
+static struct sk_buff *cfg_set_netid(void)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 1, 9999))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (network id must be 1-9999)");
+
+       if (tipc_own_addr)
+               return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                             " (cannot change network id once part of network)");
+       
+       return set_net_max(value, &tipc_net_id);
+}
+
+struct sk_buff *cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
+                          int request_space, int reply_headroom)
+{
+       struct sk_buff *rep_tlv_buf;
+
+       spin_lock_bh(&config_lock);
+
+       /* Save request and reply details in a well-known location */
+
+       req_tlv_area = request_area;
+       req_tlv_space = request_space;
+       rep_headroom = reply_headroom;
+
+       /* Check command authorization */
+
+       if (likely(orig_node == tipc_own_addr)) {
+               /* command is permitted */
+       } else if (cmd >= 0x8000) {
+               rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                                    " (cannot be done remotely)");
+               goto exit;
+       } else if (!tipc_remote_management) {
+               rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
+               goto exit;
+       }
+       else if (cmd >= 0x4000) {
+               u32 domain = 0;
+
+               if ((nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
+                   (domain != orig_node)) {
+                       rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
+                       goto exit;
+               }
+       }
+
+       /* Call appropriate processing routine */
+
+       switch (cmd) {
+       case TIPC_CMD_NOOP:
+               rep_tlv_buf = cfg_reply_none();
+               break;
+       case TIPC_CMD_GET_NODES:
+               rep_tlv_buf = node_get_nodes(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_GET_LINKS:
+               rep_tlv_buf = node_get_links(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_SHOW_LINK_STATS:
+               rep_tlv_buf = link_cmd_show_stats(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_RESET_LINK_STATS:
+               rep_tlv_buf = link_cmd_reset_stats(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_SHOW_NAME_TABLE:
+               rep_tlv_buf = nametbl_get(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_GET_BEARER_NAMES:
+               rep_tlv_buf = bearer_get_names();
+               break;
+       case TIPC_CMD_GET_MEDIA_NAMES:
+               rep_tlv_buf = media_get_names();
+               break;
+       case TIPC_CMD_SHOW_PORTS:
+               rep_tlv_buf = port_get_ports();
+               break;
+#if 0
+       case TIPC_CMD_SHOW_PORT_STATS:
+               rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_RESET_PORT_STATS:
+               rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED);
+               break;
+#endif
+       case TIPC_CMD_SET_LOG_SIZE:
+               rep_tlv_buf = log_resize(req_tlv_area, req_tlv_space);
+               break;
+       case TIPC_CMD_DUMP_LOG:
+               rep_tlv_buf = log_dump();
+               break;
+       case TIPC_CMD_SET_LINK_TOL:
+       case TIPC_CMD_SET_LINK_PRI:
+       case TIPC_CMD_SET_LINK_WINDOW:
+               rep_tlv_buf = link_cmd_config(req_tlv_area, req_tlv_space, cmd);
+               break;
+       case TIPC_CMD_ENABLE_BEARER:
+               rep_tlv_buf = cfg_enable_bearer();
+               break;
+       case TIPC_CMD_DISABLE_BEARER:
+               rep_tlv_buf = cfg_disable_bearer();
+               break;
+       case TIPC_CMD_SET_NODE_ADDR:
+               rep_tlv_buf = cfg_set_own_addr();
+               break;
+       case TIPC_CMD_SET_REMOTE_MNG:
+               rep_tlv_buf = cfg_set_remote_mng();
+               break;
+       case TIPC_CMD_SET_MAX_PORTS:
+               rep_tlv_buf = cfg_set_max_ports();
+               break;
+       case TIPC_CMD_SET_MAX_PUBL:
+               rep_tlv_buf = cfg_set_max_publications();
+               break;
+       case TIPC_CMD_SET_MAX_SUBSCR:
+               rep_tlv_buf = cfg_set_max_subscriptions();
+               break;
+       case TIPC_CMD_SET_MAX_ZONES:
+               rep_tlv_buf = cfg_set_max_zones();
+               break;
+       case TIPC_CMD_SET_MAX_CLUSTERS:
+               rep_tlv_buf = cfg_set_max_clusters();
+               break;
+       case TIPC_CMD_SET_MAX_NODES:
+               rep_tlv_buf = cfg_set_max_nodes();
+               break;
+       case TIPC_CMD_SET_MAX_SLAVES:
+               rep_tlv_buf = cfg_set_max_slaves();
+               break;
+       case TIPC_CMD_SET_NETID:
+               rep_tlv_buf = cfg_set_netid();
+               break;
+       case TIPC_CMD_GET_REMOTE_MNG:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_remote_management);
+               break;
+       case TIPC_CMD_GET_MAX_PORTS:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_ports);
+               break;
+       case TIPC_CMD_GET_MAX_PUBL:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_publications);
+               break;
+       case TIPC_CMD_GET_MAX_SUBSCR:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_subscriptions);
+               break;
+       case TIPC_CMD_GET_MAX_ZONES:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_zones);
+               break;
+       case TIPC_CMD_GET_MAX_CLUSTERS:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_clusters);
+               break;
+       case TIPC_CMD_GET_MAX_NODES:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_nodes);
+               break;
+       case TIPC_CMD_GET_MAX_SLAVES:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_max_slaves);
+               break;
+       case TIPC_CMD_GET_NETID:
+               rep_tlv_buf = cfg_reply_unsigned(tipc_net_id);
+               break;
+       default:
+               rep_tlv_buf = NULL;
+               break;
+       }
+
+       /* Return reply buffer */
+exit:
+       spin_unlock_bh(&config_lock);
+       return rep_tlv_buf;
+}
+
+static void cfg_named_msg_event(void *userdata,
+                               u32 port_ref,
+                               struct sk_buff **buf,
+                               const unchar *msg,
+                               u32 size,
+                               u32 importance, 
+                               struct tipc_portid const *orig,
+                               struct tipc_name_seq const *dest)
+{
+       struct tipc_cfg_msg_hdr *req_hdr;
+       struct tipc_cfg_msg_hdr *rep_hdr;
+       struct sk_buff *rep_buf;
+
+       /* Validate configuration message header (ignore invalid message) */
+
+       req_hdr = (struct tipc_cfg_msg_hdr *)msg;
+       if ((size < sizeof(*req_hdr)) ||
+           (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
+           (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
+               warn("discarded invalid configuration message\n");
+               return;
+       }
+
+       /* Generate reply for request (if can't, return request) */
+
+       rep_buf = cfg_do_cmd(orig->node,
+                            ntohs(req_hdr->tcm_type), 
+                            msg + sizeof(*req_hdr),
+                            size - sizeof(*req_hdr),
+                            BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
+       if (rep_buf) {
+               skb_push(rep_buf, sizeof(*rep_hdr));
+               rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
+               memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
+               rep_hdr->tcm_len = htonl(rep_buf->len);
+               rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
+       } else {
+               rep_buf = *buf;
+               *buf = NULL;
+       }
+
+       /* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
+       tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
+}
+
+int cfg_init(void)
+{
+       struct tipc_name_seq seq;
+       int res;
+
+       memset(&mng, 0, sizeof(mng));
+       INIT_LIST_HEAD(&mng.link_subscribers);
+
+       res = tipc_attach(&mng.user_ref, 0, 0);
+       if (res)
+               goto failed;
+
+       res = tipc_createport(mng.user_ref, 0, TIPC_CRITICAL_IMPORTANCE,
+                             NULL, NULL, NULL,
+                             NULL, cfg_named_msg_event, NULL,
+                             NULL, &mng.port_ref);
+       if (res)
+               goto failed;
+
+       seq.type = TIPC_CFG_SRV;
+       seq.lower = seq.upper = tipc_own_addr;
+       res = nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq);
+       if (res)
+               goto failed;
+
+       return 0;
+
+failed:
+       err("Unable to create configuration service\n");
+       tipc_detach(mng.user_ref);
+       mng.user_ref = 0;
+       return res;
+}
+
+void cfg_stop(void)
+{
+       if (mng.user_ref) {
+               tipc_detach(mng.user_ref);
+               mng.user_ref = 0;
+       }
+}
diff --git a/net/tipc/config.h b/net/tipc/config.h
new file mode 100644 (file)
index 0000000..646377d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * net/tipc/config.h: Include file for TIPC configuration service code
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_CONFIG_H
+#define _TIPC_CONFIG_H
+
+/* ---------------------------------------------------------------------- */
+
+#include <linux/tipc.h>
+#include <linux/tipc_config.h>
+#include "link.h"
+
+struct sk_buff *cfg_reply_alloc(int payload_size);
+int cfg_append_tlv(struct sk_buff *buf, int tlv_type, 
+                  void *tlv_data, int tlv_data_size);
+struct sk_buff *cfg_reply_unsigned_type(u16 tlv_type, u32 value);
+struct sk_buff *cfg_reply_string_type(u16 tlv_type, char *string);
+
+static inline struct sk_buff *cfg_reply_none(void)
+{
+       return cfg_reply_alloc(0);
+}
+
+static inline struct sk_buff *cfg_reply_unsigned(u32 value)
+{
+       return cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
+}
+
+static inline struct sk_buff *cfg_reply_error_string(char *string)
+{
+       return cfg_reply_string_type(TIPC_TLV_ERROR_STRING, string);
+}
+
+static inline struct sk_buff *cfg_reply_ultra_string(char *string)
+{
+       return cfg_reply_string_type(TIPC_TLV_ULTRA_STRING, string);
+}
+
+struct sk_buff *cfg_do_cmd(u32 orig_node, u16 cmd, 
+                          const void *req_tlv_area, int req_tlv_space, 
+                          int headroom);
+
+void cfg_link_event(u32 addr, char *name, int up);
+int  cfg_init(void);
+void cfg_stop(void);
+
+#endif
diff --git a/net/tipc/core.c b/net/tipc/core.c
new file mode 100644 (file)
index 0000000..e83ac06
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * net/tipc/core.c: TIPC module code
+ *
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/random.h>
+
+#include "core.h"
+#include "dbg.h"
+#include "ref.h"
+#include "net.h"
+#include "user_reg.h"
+#include "name_table.h"
+#include "subscr.h"
+#include "config.h"
+
+int  eth_media_start(void);
+void eth_media_stop(void);
+int  handler_start(void);
+void handler_stop(void);
+int  socket_init(void);
+void socket_stop(void);
+int  netlink_start(void);
+void netlink_stop(void);
+
+#define MOD_NAME "tipc_start: "
+
+#ifndef CONFIG_TIPC_ZONES
+#define CONFIG_TIPC_ZONES 3
+#endif
+
+#ifndef CONFIG_TIPC_CLUSTERS
+#define CONFIG_TIPC_CLUSTERS 1
+#endif
+
+#ifndef CONFIG_TIPC_NODES
+#define CONFIG_TIPC_NODES 255
+#endif
+
+#ifndef CONFIG_TIPC_SLAVE_NODES
+#define CONFIG_TIPC_SLAVE_NODES 0
+#endif
+
+#ifndef CONFIG_TIPC_PORTS
+#define CONFIG_TIPC_PORTS 8191
+#endif
+
+#ifndef CONFIG_TIPC_LOG
+#define CONFIG_TIPC_LOG 0
+#endif
+
+/* global variables used by multiple sub-systems within TIPC */
+
+int tipc_mode = TIPC_NOT_RUNNING;
+int tipc_random;
+atomic_t tipc_user_count = ATOMIC_INIT(0);
+
+const char tipc_alphabet[] = 
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+
+/* configurable TIPC parameters */
+
+u32 tipc_own_addr;
+int tipc_max_zones;
+int tipc_max_clusters;
+int tipc_max_nodes;
+int tipc_max_slaves;
+int tipc_max_ports;
+int tipc_max_subscriptions;
+int tipc_max_publications;
+int tipc_net_id;
+int tipc_remote_management;
+
+
+int tipc_get_mode(void)
+{
+       return tipc_mode;
+}
+
+/**
+ * stop_net - shut down TIPC networking sub-systems
+ */
+
+void stop_net(void)
+{
+       eth_media_stop();
+       tipc_stop_net();
+}
+
+/**
+ * start_net - start TIPC networking sub-systems
+ */
+
+int start_net(void)
+{
+       int res;
+
+       if ((res = tipc_start_net()) ||
+           (res = eth_media_start())) {
+               stop_net();
+       }
+       return res;
+}
+
+/**
+ * stop_core - switch TIPC from SINGLE NODE to NOT RUNNING mode
+ */
+
+void stop_core(void)
+{
+       if (tipc_mode != TIPC_NODE_MODE)
+               return;
+
+       tipc_mode = TIPC_NOT_RUNNING;
+
+       netlink_stop();
+       handler_stop();
+       cfg_stop();
+       subscr_stop();
+       reg_stop();
+       nametbl_stop();
+       ref_table_stop();
+       socket_stop();
+}
+
+/**
+ * start_core - switch TIPC from NOT RUNNING to SINGLE NODE mode
+ */
+
+int start_core(void)
+{
+       int res;
+
+       if (tipc_mode != TIPC_NOT_RUNNING)
+               return -ENOPROTOOPT;
+
+       get_random_bytes(&tipc_random, sizeof(tipc_random));
+       tipc_mode = TIPC_NODE_MODE;
+
+       if ((res = handler_start()) || 
+           (res = ref_table_init(tipc_max_ports + tipc_max_subscriptions,
+                                 tipc_random)) ||
+           (res = reg_start()) ||
+           (res = nametbl_init()) ||
+            (res = k_signal((Handler)subscr_start, 0)) ||
+           (res = k_signal((Handler)cfg_init, 0)) || 
+           (res = netlink_start()) ||
+           (res = socket_init())) {
+               stop_core();
+       }
+       return res;
+}
+
+
+static int __init tipc_init(void)
+{
+       int res;
+
+       log_reinit(CONFIG_TIPC_LOG);
+       info("Activated (compiled " __DATE__ " " __TIME__ ")\n");
+
+       tipc_own_addr = 0;
+       tipc_remote_management = 1;
+       tipc_max_publications = 10000;
+       tipc_max_subscriptions = 2000;
+       tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
+       tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 511);
+       tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
+       tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
+       tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
+       tipc_net_id = 4711;
+
+       if ((res = start_core()))
+               err("Unable to start in single node mode\n");
+       else    
+               info("Started in single node mode\n");
+        return res;
+}
+
+static void __exit tipc_exit(void)
+{
+       stop_net();
+       stop_core();
+       info("Deactivated\n");
+       log_stop();
+}
+
+module_init(tipc_init);
+module_exit(tipc_exit);
+
+MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* Native TIPC API for kernel-space applications (see tipc.h) */
+
+EXPORT_SYMBOL(tipc_attach);
+EXPORT_SYMBOL(tipc_detach);
+EXPORT_SYMBOL(tipc_get_addr);
+EXPORT_SYMBOL(tipc_get_mode);
+EXPORT_SYMBOL(tipc_createport);
+EXPORT_SYMBOL(tipc_deleteport);
+EXPORT_SYMBOL(tipc_ownidentity);
+EXPORT_SYMBOL(tipc_portimportance);
+EXPORT_SYMBOL(tipc_set_portimportance);
+EXPORT_SYMBOL(tipc_portunreliable);
+EXPORT_SYMBOL(tipc_set_portunreliable);
+EXPORT_SYMBOL(tipc_portunreturnable);
+EXPORT_SYMBOL(tipc_set_portunreturnable);
+EXPORT_SYMBOL(tipc_publish);
+EXPORT_SYMBOL(tipc_withdraw);
+EXPORT_SYMBOL(tipc_connect2port);
+EXPORT_SYMBOL(tipc_disconnect);
+EXPORT_SYMBOL(tipc_shutdown);
+EXPORT_SYMBOL(tipc_isconnected);
+EXPORT_SYMBOL(tipc_peer);
+EXPORT_SYMBOL(tipc_ref_valid);
+EXPORT_SYMBOL(tipc_send);
+EXPORT_SYMBOL(tipc_send_buf);
+EXPORT_SYMBOL(tipc_send2name);
+EXPORT_SYMBOL(tipc_forward2name);
+EXPORT_SYMBOL(tipc_send_buf2name);
+EXPORT_SYMBOL(tipc_forward_buf2name);
+EXPORT_SYMBOL(tipc_send2port);
+EXPORT_SYMBOL(tipc_forward2port);
+EXPORT_SYMBOL(tipc_send_buf2port);
+EXPORT_SYMBOL(tipc_forward_buf2port);
+EXPORT_SYMBOL(tipc_multicast);
+/* EXPORT_SYMBOL(tipc_multicast_buf); not available yet */
+EXPORT_SYMBOL(tipc_ispublished);
+EXPORT_SYMBOL(tipc_available_nodes);
+
+/* TIPC API for external bearers (see tipc_bearer.h) */
+
+EXPORT_SYMBOL(tipc_block_bearer);
+EXPORT_SYMBOL(tipc_continue); 
+EXPORT_SYMBOL(tipc_disable_bearer);
+EXPORT_SYMBOL(tipc_enable_bearer);
+EXPORT_SYMBOL(tipc_recv_msg);
+EXPORT_SYMBOL(tipc_register_media); 
+
+/* TIPC API for external APIs (see tipc_port.h) */
+
+EXPORT_SYMBOL(tipc_createport_raw);
+EXPORT_SYMBOL(tipc_set_msg_option);
+EXPORT_SYMBOL(tipc_reject_msg);
+EXPORT_SYMBOL(tipc_send_buf_fast);
+EXPORT_SYMBOL(tipc_acknowledge);
+EXPORT_SYMBOL(tipc_get_port);
+EXPORT_SYMBOL(tipc_get_handle);
+
diff --git a/net/tipc/core.h b/net/tipc/core.h
new file mode 100644 (file)
index 0000000..b69b60b
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * net/tipc/core.h: Include file for TIPC global declarations
+ * 
+ * Copyright (c) 2005-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_CORE_H
+#define _TIPC_CORE_H
+
+#include <net/tipc/tipc.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>  
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+
+/*
+ * TIPC debugging code
+ */
+
+#define assert(i)  BUG_ON(!(i))
+
+struct tipc_msg;
+extern struct print_buf *CONS, *LOG;
+extern struct print_buf *TEE(struct print_buf *, struct print_buf *);
+void msg_print(struct print_buf*,struct tipc_msg *,const char*);
+void tipc_printf(struct print_buf *, const char *fmt, ...);
+void tipc_dump(struct print_buf*,const char *fmt, ...);
+
+#ifdef CONFIG_TIPC_DEBUG
+
+/*
+ * TIPC debug support included:
+ * - system messages are printed to TIPC_OUTPUT print buffer
+ * - debug messages are printed to DBG_OUTPUT print buffer
+ */
+
+#define err(fmt, arg...)  tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg)
+#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
+#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
+
+#define dbg(fmt, arg...)  do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
+#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) msg_print(DBG_OUTPUT, msg, txt);} while(0)
+#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+
+
+/*     
+ * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer,
+ * while DBG_OUTPUT is the null print buffer.  These defaults can be changed
+ * here, or on a per .c file basis, by redefining these symbols.  The following
+ * print buffer options are available:
+ *
+ * NULL                        : Output to null print buffer (i.e. print nowhere)
+ * CONS                        : Output to system console
+ * LOG                 : Output to TIPC log buffer 
+ * &buf                : Output to user-defined buffer (struct print_buf *)
+ * TEE(&buf_a,&buf_b)  : Output to two print buffers (eg. TEE(CONS,LOG) )
+ */
+
+#ifndef TIPC_OUTPUT
+#define TIPC_OUTPUT TEE(CONS,LOG)
+#endif
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT NULL
+#endif
+
+#else
+
+#ifndef DBG_OUTPUT
+#define DBG_OUTPUT NULL
+#endif
+
+/*
+ * TIPC debug support not included:
+ * - system messages are printed to system console
+ * - debug messages are not printed
+ */
+
+#define err(fmt, arg...)  printk(KERN_ERR "TIPC: " fmt , ## arg)
+#define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg)
+#define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg)
+
+#define dbg(fmt, arg...) do {} while (0)
+#define msg_dbg(msg,txt) do {} while (0)
+#define dump(fmt,arg...) do {} while (0)
+
+#endif                   
+
+
+/* 
+ * TIPC-specific error codes
+ */
+
+#define ELINKCONG EAGAIN       /* link congestion <=> resource unavailable */
+
+/*
+ * Global configuration variables
+ */
+
+extern u32 tipc_own_addr;
+extern int tipc_max_zones;
+extern int tipc_max_clusters;
+extern int tipc_max_nodes;
+extern int tipc_max_slaves;
+extern int tipc_max_ports;
+extern int tipc_max_subscriptions;
+extern int tipc_max_publications;
+extern int tipc_net_id;
+extern int tipc_remote_management;
+
+/*
+ * Other global variables
+ */
+
+extern int tipc_mode;
+extern int tipc_random;
+extern const char tipc_alphabet[];
+extern atomic_t tipc_user_count;
+
+
+/*
+ * Routines available to privileged subsystems
+ */
+
+extern int  start_core(void);
+extern void stop_core(void);
+extern int  start_net(void);
+extern void stop_net(void);
+
+static inline int delimit(int val, int min, int max)
+{
+       if (val > max)
+               return max;
+       if (val < min)
+               return min;
+       return val;
+}
+
+
+/*
+ * TIPC timer and signal code
+ */
+
+typedef void (*Handler) (unsigned long);
+
+u32 k_signal(Handler routine, unsigned long argument);
+
+/**
+ * k_init_timer - initialize a timer
+ * @timer: pointer to timer structure
+ * @routine: pointer to routine to invoke when timer expires
+ * @argument: value to pass to routine when timer expires
+ * 
+ * Timer must be initialized before use (and terminated when no longer needed).
+ */
+
+static inline void k_init_timer(struct timer_list *timer, Handler routine, 
+                               unsigned long argument)
+{
+       dbg("initializing timer %p\n", timer);
+       init_timer(timer);
+       timer->function = routine;
+       timer->data = argument;
+}
+
+/**
+ * k_start_timer - start a timer
+ * @timer: pointer to timer structure
+ * @msec: time to delay (in ms)
+ * 
+ * Schedules a previously initialized timer for later execution.
+ * If timer is already running, the new timeout overrides the previous request.
+ * 
+ * To ensure the timer doesn't expire before the specified delay elapses,
+ * the amount of delay is rounded up when converting to the jiffies
+ * then an additional jiffy is added to account for the fact that 
+ * the starting time may be in the middle of the current jiffy.
+ */
+
+static inline void k_start_timer(struct timer_list *timer, unsigned long msec)
+{
+       dbg("starting timer %p for %u\n", timer, msec);
+       mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1);
+}
+
+/**
+ * k_cancel_timer - cancel a timer
+ * @timer: pointer to timer structure
+ * 
+ * Cancels a previously initialized timer.  
+ * Can be called safely even if the timer is already inactive.
+ * 
+ * WARNING: Must not be called when holding locks required by the timer's
+ *          timeout routine, otherwise deadlock can occur on SMP systems!
+ */
+
+static inline void k_cancel_timer(struct timer_list *timer)
+{
+       dbg("cancelling timer %p\n", timer);
+       del_timer_sync(timer);
+}
+
+/**
+ * k_term_timer - terminate a timer
+ * @timer: pointer to timer structure
+ * 
+ * Prevents further use of a previously initialized timer.
+ * 
+ * WARNING: Caller must ensure timer isn't currently running.
+ * 
+ * (Do not "enhance" this routine to automatically cancel an active timer,
+ * otherwise deadlock can arise when a timeout routine calls k_term_timer.)
+ */
+
+static inline void k_term_timer(struct timer_list *timer)
+{
+       dbg("terminating timer %p\n", timer);
+}
+
+
+/*
+ * TIPC message buffer code
+ *
+ * TIPC message buffer headroom leaves room for 14 byte Ethernet header, 
+ * while ensuring TIPC header is word aligned for quicker access
+ */
+
+#define BUF_HEADROOM 16u 
+
+struct tipc_skb_cb {
+       void *handle;
+};
+
+#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
+
+
+static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
+{
+       return (struct tipc_msg *)skb->data;
+}
+
+/**
+ * buf_acquire - creates a TIPC message buffer
+ * @size: message size (including TIPC header)
+ *
+ * Returns a new buffer.  Space is reserved for a data link header.
+ */
+
+static inline struct sk_buff *buf_acquire(u32 size)
+{
+       struct sk_buff *skb;
+       unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
+
+       skb = alloc_skb(buf_size, GFP_ATOMIC);
+       if (skb) {
+               skb_reserve(skb, BUF_HEADROOM);
+               skb_put(skb, size);
+               skb->next = NULL;
+       }
+       return skb;
+}
+
+/**
+ * buf_discard - frees a TIPC message buffer
+ * @skb: message buffer
+ *
+ * Frees a new buffer.  If passed NULL, just returns.
+ */
+
+static inline void buf_discard(struct sk_buff *skb)
+{
+       if (likely(skb != NULL))
+               kfree_skb(skb);
+}
+
+#endif                 
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
new file mode 100644 (file)
index 0000000..7ed60a1
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * net/tipc/dbg.c: TIPC print buffer routines for debuggign
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+
+#define MAX_STRING 512
+
+static char print_string[MAX_STRING];
+static spinlock_t print_lock = SPIN_LOCK_UNLOCKED;
+
+static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
+struct print_buf *CONS = &cons_buf;
+
+static struct print_buf log_buf = { NULL, 0, NULL, NULL };
+struct print_buf *LOG = &log_buf;
+
+
+#define FORMAT(PTR,LEN,FMT) \
+{\
+       va_list args;\
+       va_start(args, FMT);\
+       LEN = vsprintf(PTR, FMT, args);\
+       va_end(args);\
+       *(PTR + LEN) = '\0';\
+}
+
+/*
+ * Locking policy when using print buffers.
+ *
+ * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
+ *    simultaneous use of the print buffer(s) being manipulated.
+ * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
+ *    'print_string' and to protect its print buffer(s).
+ * 3) TEE() uses 'print_lock' to protect its print buffer(s).
+ * 4) Routines of the form log_XXX() uses 'print_lock' to protect LOG.
+ */
+
+/**
+ * printbuf_init - initialize print buffer to empty
+ */
+
+void printbuf_init(struct print_buf *pb, char *raw, u32 sz)
+{
+       if (!pb || !raw || (sz < (MAX_STRING + 1)))
+               return;
+
+       pb->crs = pb->buf = raw;
+       pb->size = sz;
+       pb->next = 0;
+       pb->buf[0] = 0;
+       pb->buf[sz-1] = ~0;
+}
+
+/**
+ * printbuf_reset - reinitialize print buffer to empty state
+ */
+
+void printbuf_reset(struct print_buf *pb)
+{
+       if (pb && pb->buf)
+               printbuf_init(pb, pb->buf, pb->size);
+}
+
+/**
+ * printbuf_empty - test if print buffer is in empty state
+ */
+
+int printbuf_empty(struct print_buf *pb)
+{
+       return (!pb || !pb->buf || (pb->crs == pb->buf));
+}
+
+/**
+ * printbuf_validate - check for print buffer overflow
+ * 
+ * Verifies that a print buffer has captured all data written to it. 
+ * If data has been lost, linearize buffer and prepend an error message
+ * 
+ * Returns length of print buffer data string (including trailing NULL)
+ */
+
+int printbuf_validate(struct print_buf *pb)
+{
+        char *err = "             *** PRINT BUFFER WRAPPED AROUND ***\n";
+        char *cp_buf;
+        struct print_buf cb;
+
+       if (!pb || !pb->buf)
+               return 0;
+
+       if (pb->buf[pb->size - 1] == '\0') {
+                cp_buf = kmalloc(pb->size, GFP_ATOMIC);
+                if (cp_buf != NULL){
+                        printbuf_init(&cb, cp_buf, pb->size);
+                        printbuf_move(&cb, pb);
+                        printbuf_move(pb, &cb);
+                        kfree(cp_buf);
+                        memcpy(pb->buf, err, strlen(err));
+                } else {
+                        printbuf_reset(pb);
+                        tipc_printf(pb, err);
+                }
+       }
+       return (pb->crs - pb->buf + 1);
+}
+
+/**
+ * printbuf_move - move print buffer contents to another print buffer
+ * 
+ * Current contents of destination print buffer (if any) are discarded.
+ * Source print buffer becomes empty if a successful move occurs.
+ */
+
+void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
+{
+       int len;
+
+       /* Handle the cases where contents can't be moved */
+
+       if (!pb_to || !pb_to->buf)
+               return;
+
+       if (!pb_from || !pb_from->buf) {
+               printbuf_reset(pb_to);
+               return;
+       }
+
+       if (pb_to->size < pb_from->size) {
+               printbuf_reset(pb_to);
+               tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
+               return;
+       }
+
+       /* Copy data from char after cursor to end (if used) */
+       len = pb_from->buf + pb_from->size - pb_from->crs - 2;
+       if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
+               strcpy(pb_to->buf, pb_from->crs + 1);
+               pb_to->crs = pb_to->buf + len;
+       } else
+               pb_to->crs = pb_to->buf;
+
+       /* Copy data from start to cursor (always) */
+       len = pb_from->crs - pb_from->buf;
+       strcpy(pb_to->crs, pb_from->buf);
+       pb_to->crs += len;
+
+       printbuf_reset(pb_from);
+}
+
+/**
+ * tipc_printf - append formatted output to print buffer chain
+ */
+
+void tipc_printf(struct print_buf *pb, const char *fmt, ...)
+{
+       int chars_to_add;
+       int chars_left;
+       char save_char;
+       struct print_buf *pb_next;
+
+       spin_lock_bh(&print_lock);
+       FORMAT(print_string, chars_to_add, fmt);
+       if (chars_to_add >= MAX_STRING)
+               strcpy(print_string, "*** STRING TOO LONG ***");
+
+       while (pb) {
+               if (pb == CONS)
+                       printk(print_string);
+               else if (pb->buf) {
+                       chars_left = pb->buf + pb->size - pb->crs - 1;
+                       if (chars_to_add <= chars_left) {
+                               strcpy(pb->crs, print_string);
+                               pb->crs += chars_to_add;
+                       } else {
+                               strcpy(pb->buf, print_string + chars_left);
+                                save_char = print_string[chars_left];
+                                print_string[chars_left] = 0;
+                                strcpy(pb->crs, print_string);
+                                print_string[chars_left] = save_char;
+                                pb->crs = pb->buf + chars_to_add - chars_left;
+                        }
+                }
+               pb_next = pb->next;
+               pb->next = 0;
+               pb = pb_next;
+       }
+       spin_unlock_bh(&print_lock);
+}
+
+/**
+ * TEE - perform next output operation on both print buffers  
+ */
+
+struct print_buf *TEE(struct print_buf *b0, struct print_buf *b1)
+{
+       struct print_buf *pb = b0;
+
+       if (!b0 || (b0 == b1))
+               return b1;
+       if (!b1)
+               return b0;
+
+       spin_lock_bh(&print_lock);
+       while (pb->next) {
+               if ((pb->next == b1) || (pb->next == b0))
+                       pb->next = pb->next->next;
+               else
+                       pb = pb->next;
+       }
+       pb->next = b1;
+       spin_unlock_bh(&print_lock);
+       return b0;
+}
+
+/**
+ * print_to_console - write string of bytes to console in multiple chunks
+ */
+
+static void print_to_console(char *crs, int len)
+{
+       int rest = len;
+
+       while (rest > 0) {
+               int sz = rest < MAX_STRING ? rest : MAX_STRING;
+               char c = crs[sz];
+
+               crs[sz] = 0;
+               printk((const char *)crs);
+               crs[sz] = c;
+               rest -= sz;
+               crs += sz;
+       }
+}
+
+/**
+ * printbuf_dump - write print buffer contents to console
+ */
+
+static void printbuf_dump(struct print_buf *pb)
+{
+       int len;
+
+       /* Dump print buffer from char after cursor to end (if used) */
+       len = pb->buf + pb->size - pb->crs - 2;
+       if ((pb->buf[pb->size - 1] == 0) && (len > 0))
+               print_to_console(pb->crs + 1, len);
+
+       /* Dump print buffer from start to cursor (always) */
+       len = pb->crs - pb->buf;
+       print_to_console(pb->buf, len);
+}
+
+/**
+ * tipc_dump - dump non-console print buffer(s) to console
+ */
+
+void tipc_dump(struct print_buf *pb, const char *fmt, ...)
+{
+       int len;
+
+       spin_lock_bh(&print_lock);
+       FORMAT(CONS->buf, len, fmt);
+       printk(CONS->buf);
+
+       for (; pb; pb = pb->next) {
+               if (pb == CONS)
+                       continue;
+               printk("\n---- Start of dump,%s log ----\n\n", 
+                      (pb == LOG) ? "global" : "local");
+               printbuf_dump(pb);
+               printbuf_reset(pb);
+               printk("\n-------- End of dump --------\n");
+       }
+       spin_unlock_bh(&print_lock);
+}
+
+/**
+ * log_stop - free up TIPC log print buffer 
+ */
+
+void log_stop(void)
+{
+       spin_lock_bh(&print_lock);
+       if (LOG->buf) {
+               kfree(LOG->buf);
+               LOG->buf = NULL;
+       }
+       spin_unlock_bh(&print_lock);
+}
+
+/**
+ * log_reinit - set TIPC log print buffer to specified size
+ */
+
+void log_reinit(int log_size)
+{
+       log_stop();
+
+       if (log_size) {
+               if (log_size <= MAX_STRING)
+                       log_size = MAX_STRING + 1;
+               spin_lock_bh(&print_lock);
+               printbuf_init(LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
+               spin_unlock_bh(&print_lock);
+       }
+}
+
+/**
+ * log_resize - reconfigure size of TIPC log buffer
+ */
+
+struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space)
+{
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       value = *(u32 *)TLV_DATA(req_tlv_area);
+       value = ntohl(value);
+       if (value != delimit(value, 0, 32768))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (log size must be 0-32768)");
+       log_reinit(value);
+       return cfg_reply_none();
+}
+
+/**
+ * log_dump - capture TIPC log buffer contents in configuration message
+ */
+
+struct sk_buff *log_dump(void)
+{
+       struct sk_buff *reply;
+
+       spin_lock_bh(&print_lock);
+       if (!LOG->buf)
+               reply = cfg_reply_ultra_string("log not activated\n");
+       else if (printbuf_empty(LOG))
+               reply = cfg_reply_ultra_string("log is empty\n");
+       else {
+               struct tlv_desc *rep_tlv;
+               struct print_buf pb;
+               int str_len;
+
+               str_len = min(LOG->size, 32768u);
+               reply = cfg_reply_alloc(TLV_SPACE(str_len));
+               if (reply) {
+                       rep_tlv = (struct tlv_desc *)reply->data;
+                       printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
+                       printbuf_move(&pb, LOG);
+                       str_len = strlen(TLV_DATA(rep_tlv)) + 1;
+                       skb_put(reply, TLV_SPACE(str_len));
+                       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+               }
+       }
+       spin_unlock_bh(&print_lock);
+       return reply;
+}
+
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
new file mode 100644 (file)
index 0000000..c6b2a64
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * net/tipc/dbg.h: Include file for TIPC print buffer routines
+ * 
+ * Copyright (c) 1997-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_DBG_H
+#define _TIPC_DBG_H
+
+struct print_buf {
+       char *buf;
+       u32 size;
+       char *crs;
+       struct print_buf *next;
+};
+
+void printbuf_init(struct print_buf *pb, char *buf, u32 sz);
+void printbuf_reset(struct print_buf *pb);
+int  printbuf_empty(struct print_buf *pb);
+int  printbuf_validate(struct print_buf *pb);
+void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
+
+void log_reinit(int log_size);
+void log_stop(void);
+
+struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *log_dump(void);
+
+#endif
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
new file mode 100644 (file)
index 0000000..b106ef1
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * net/tipc/discover.c
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "link.h"
+#include "zone.h"
+#include "discover.h"
+#include "port.h"
+#include "name_table.h"
+
+#define TIPC_LINK_REQ_INIT     125     /* min delay during bearer start up */
+#define TIPC_LINK_REQ_FAST     2000    /* normal delay if bearer has no links */
+#define TIPC_LINK_REQ_SLOW     600000  /* normal delay if bearer has links */
+
+#if 0
+#define  GET_NODE_INFO         300
+#define  GET_NODE_INFO_RESULT  301
+#define  FORWARD_LINK_PROBE    302
+#define  LINK_REQUEST_REJECTED 303
+#define  LINK_REQUEST_ACCEPTED 304
+#define  DROP_LINK_REQUEST     305
+#define  CHECK_LINK_COUNT      306
+#endif
+
+/* 
+ * TODO: Most of the inter-cluster setup stuff should be
+ * rewritten, and be made conformant with specification.
+ */ 
+
+
+/**
+ * struct link_req - information about an ongoing link setup request
+ * @bearer: bearer issuing requests
+ * @dest: destination address for request messages
+ * @buf: request message to be (repeatedly) sent
+ * @timer: timer governing period between requests
+ * @timer_intv: current interval between requests (in ms)
+ */
+struct link_req {
+       struct bearer *bearer;
+       struct tipc_media_addr dest;
+       struct sk_buff *buf;
+       struct timer_list timer;
+       unsigned int timer_intv;
+};
+
+
+#if 0
+int disc_create_link(const struct tipc_link_create *argv) 
+{
+       /* 
+        * Code for inter cluster link setup here 
+        */
+       return TIPC_OK;
+}
+#endif
+
+/*
+ * disc_lost_link(): A link has lost contact
+ */
+
+void disc_link_event(u32 addr, char *name, int up) 
+{
+       if (in_own_cluster(addr))
+               return;
+       /* 
+        * Code for inter cluster link setup here 
+        */
+}
+
+/** 
+ * disc_init_msg - initialize a link setup message
+ * @type: message type (request or response)
+ * @req_links: number of links associated with message
+ * @dest_domain: network domain of node(s) which should respond to message
+ * @b_ptr: ptr to bearer issuing message
+ */
+
+struct sk_buff *disc_init_msg(u32 type,
+                             u32 req_links,
+                             u32 dest_domain,
+                             struct bearer *b_ptr)
+{
+       struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
+       struct tipc_msg *msg;
+
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE,
+                        dest_domain);
+               msg_set_non_seq(msg);
+               msg_set_req_links(msg, req_links);
+               msg_set_dest_domain(msg, dest_domain);
+               msg_set_bc_netid(msg, tipc_net_id);
+               msg_set_media_addr(msg, &b_ptr->publ.addr);
+       }
+       return buf;
+}
+
+/**
+ * disc_recv_msg - handle incoming link setup message (request or response)
+ * @buf: buffer containing message
+ */
+
+void disc_recv_msg(struct sk_buff *buf)
+{
+       struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle;
+       struct link *link;
+       struct tipc_media_addr media_addr;
+       struct tipc_msg *msg = buf_msg(buf);
+       u32 dest = msg_dest_domain(msg);
+       u32 orig = msg_prevnode(msg);
+       u32 net_id = msg_bc_netid(msg);
+       u32 type = msg_type(msg);
+
+       msg_get_media_addr(msg,&media_addr);
+       msg_dbg(msg, "RECV:");
+       buf_discard(buf);
+
+       if (net_id != tipc_net_id)
+               return;
+       if (!addr_domain_valid(dest))
+               return;
+       if (!addr_node_valid(orig))
+               return;
+       if (orig == tipc_own_addr)
+               return;
+       if (!in_scope(dest, tipc_own_addr))
+               return;
+       if (is_slave(tipc_own_addr) && is_slave(orig))
+               return;
+       if (is_slave(orig) && !in_own_cluster(orig))
+               return;
+       if (in_own_cluster(orig)) {
+               /* Always accept link here */
+               struct sk_buff *rbuf;
+               struct tipc_media_addr *addr;
+               struct node *n_ptr = node_find(orig);
+               int link_up;
+               dbg(" in own cluster\n");
+               if (n_ptr == NULL) {
+                       n_ptr = node_create(orig);
+               }
+               if (n_ptr == NULL) {
+                       warn("Memory squeeze; Failed to create node\n");
+                       return;
+               }
+               spin_lock_bh(&n_ptr->lock);
+               link = n_ptr->links[b_ptr->identity];
+               if (!link) {
+                       dbg("creating link\n");
+                       link = link_create(b_ptr, orig, &media_addr);
+                       if (!link) {
+                               spin_unlock_bh(&n_ptr->lock);                
+                               return;
+                       }
+               }
+               addr = &link->media_addr;
+               if (memcmp(addr, &media_addr, sizeof(*addr))) {
+                       char addr_string[16];
+
+                       warn("New bearer address for %s\n", 
+                            addr_string_fill(addr_string, orig));
+                       memcpy(addr, &media_addr, sizeof(*addr));
+                       link_reset(link);     
+               }
+               link_up = link_is_up(link);
+               spin_unlock_bh(&n_ptr->lock);                
+               if ((type == DSC_RESP_MSG) || link_up)
+                       return;
+               rbuf = disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
+               if (rbuf != NULL) {
+                       msg_dbg(buf_msg(rbuf),"SEND:");
+                       b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr);
+                       buf_discard(rbuf);
+               }
+       }
+}
+
+/**
+ * disc_stop_link_req - stop sending periodic link setup requests
+ * @req: ptr to link request structure
+ */
+
+void disc_stop_link_req(struct link_req *req) 
+{
+       if (!req)
+               return;
+               
+       k_cancel_timer(&req->timer);
+       k_term_timer(&req->timer);
+       buf_discard(req->buf);
+       kfree(req);
+} 
+
+/**
+ * disc_update_link_req - update frequency of periodic link setup requests
+ * @req: ptr to link request structure
+ */
+
+void disc_update_link_req(struct link_req *req) 
+{
+       if (!req)
+               return;
+
+       if (req->timer_intv == TIPC_LINK_REQ_SLOW) {
+               if (!req->bearer->nodes.count) {
+                       req->timer_intv = TIPC_LINK_REQ_FAST;
+                       k_start_timer(&req->timer, req->timer_intv);
+               }
+       } else if (req->timer_intv == TIPC_LINK_REQ_FAST) {
+               if (req->bearer->nodes.count) {
+                       req->timer_intv = TIPC_LINK_REQ_SLOW;
+                       k_start_timer(&req->timer, req->timer_intv);
+               }
+       } else {
+               /* leave timer "as is" if haven't yet reached a "normal" rate */
+       }
+} 
+
+/**
+ * disc_timeout - send a periodic link setup request
+ * @req: ptr to link request structure
+ * 
+ * Called whenever a link setup request timer associated with a bearer expires.
+ */
+
+static void disc_timeout(struct link_req *req) 
+{
+       spin_lock_bh(&req->bearer->publ.lock);
+
+       req->bearer->media->send_msg(req->buf, &req->bearer->publ, &req->dest);
+
+       if ((req->timer_intv == TIPC_LINK_REQ_SLOW) ||
+           (req->timer_intv == TIPC_LINK_REQ_FAST)) {
+               /* leave timer interval "as is" if already at a "normal" rate */
+       } else {
+               req->timer_intv *= 2;
+               if (req->timer_intv > TIPC_LINK_REQ_SLOW)
+                       req->timer_intv = TIPC_LINK_REQ_SLOW;
+               if ((req->timer_intv == TIPC_LINK_REQ_FAST) && 
+                   (req->bearer->nodes.count))
+                       req->timer_intv = TIPC_LINK_REQ_SLOW;
+       }
+       k_start_timer(&req->timer, req->timer_intv);
+
+       spin_unlock_bh(&req->bearer->publ.lock);
+}
+
+/**
+ * disc_init_link_req - start sending periodic link setup requests
+ * @b_ptr: ptr to bearer issuing requests
+ * @dest: destination address for request messages
+ * @dest_domain: network domain of node(s) which should respond to message
+ * @req_links: max number of desired links
+ * 
+ * Returns pointer to link request structure, or NULL if unable to create.
+ */
+
+struct link_req *disc_init_link_req(struct bearer *b_ptr, 
+                                   const struct tipc_media_addr *dest,
+                                   u32 dest_domain,
+                                   u32 req_links) 
+{
+       struct link_req *req;
+
+       req = (struct link_req *)kmalloc(sizeof(*req), GFP_ATOMIC);
+       if (!req)
+               return NULL;
+
+       req->buf = disc_init_msg(DSC_REQ_MSG, req_links, dest_domain, b_ptr);
+       if (!req->buf) {
+               kfree(req);
+               return NULL;
+       }
+
+       memcpy(&req->dest, dest, sizeof(*dest));
+       req->bearer = b_ptr;
+       req->timer_intv = TIPC_LINK_REQ_INIT;
+       k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
+       k_start_timer(&req->timer, req->timer_intv);
+       return req;
+} 
+
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
new file mode 100644 (file)
index 0000000..2a6114d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * net/tipc/discover.h
+ *
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_DISCOVER_H
+#define _TIPC_DISCOVER_H
+
+#include <linux/tipc.h>
+
+struct link_req;
+
+struct link_req *disc_init_link_req(struct bearer *b_ptr, 
+                                   const struct tipc_media_addr *dest,
+                                   u32 dest_domain,
+                                   u32 req_links);
+void disc_update_link_req(struct link_req *req);
+void disc_stop_link_req(struct link_req *req);
+
+void disc_recv_msg(struct sk_buff *buf);
+
+void disc_link_event(u32 addr, char *name, int up);
+#if 0
+int  disc_create_link(const struct tipc_link_create *argv);
+#endif
+
+#endif
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
new file mode 100644 (file)
index 0000000..34d0462
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * net/tipc/eth_media.c: Ethernet bearer support for TIPC
+ * 
+ * Copyright (c) 2001-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <net/tipc/tipc.h>
+#include <net/tipc/tipc_bearer.h>
+#include <net/tipc/tipc_msg.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+
+#define MAX_ETH_BEARERS                2
+#define TIPC_PROTOCOL          0x88ca
+#define ETH_LINK_PRIORITY      10
+#define ETH_LINK_TOLERANCE     TIPC_DEF_LINK_TOL
+
+
+/**
+ * struct eth_bearer - Ethernet bearer data structure
+ * @bearer: ptr to associated "generic" bearer structure
+ * @dev: ptr to associated Ethernet network device
+ * @tipc_packet_type: used in binding TIPC to Ethernet driver
+ */
+struct eth_bearer {
+       struct tipc_bearer *bearer;
+       struct net_device *dev;
+       struct packet_type tipc_packet_type;
+};
+
+static struct eth_bearer eth_bearers[MAX_ETH_BEARERS];
+static int eth_started = 0;
+static struct notifier_block notifier;
+
+/**
+ * send_msg - send a TIPC message out over an Ethernet interface 
+ */
+
+static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, 
+                   struct tipc_media_addr *dest)
+{
+       struct sk_buff *clone;
+       struct net_device *dev;
+
+       clone = skb_clone(buf, GFP_ATOMIC);
+       if (clone) {
+               clone->nh.raw = clone->data;
+               dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
+               clone->dev = dev;
+               dev->hard_header(clone, dev, TIPC_PROTOCOL, 
+                                &dest->dev_addr.eth_addr,
+                                dev->dev_addr, clone->len);
+               dev_queue_xmit(clone);
+       }
+       return TIPC_OK;
+}
+
+/**
+ * recv_msg - handle incoming TIPC message from an Ethernet interface
+ * 
+ * Routine truncates any Ethernet padding/CRC appended to the message,
+ * and ensures message size matches actual length
+ */
+
+static int recv_msg(struct sk_buff *buf, struct net_device *dev, 
+                   struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
+       u32 size;
+
+       if (likely(eb_ptr->bearer)) {
+               size = msg_size((struct tipc_msg *)buf->data);
+               skb_trim(buf, size);
+               if (likely(buf->len == size)) {
+                       buf->next = NULL;
+                       tipc_recv_msg(buf, eb_ptr->bearer);
+               } else {
+                       kfree_skb(buf);
+               }
+       } else {
+               kfree_skb(buf);
+       }
+       return TIPC_OK;
+}
+
+/**
+ * enable_bearer - attach TIPC bearer to an Ethernet interface 
+ */
+
+static int enable_bearer(struct tipc_bearer *tb_ptr)
+{
+       struct net_device *dev = dev_base;
+       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 &&
+              (memcmp(dev->name, driver_name, strlen(dev->name)))) {
+               dev = dev->next;
+       }
+       if (!dev)
+               return -ENODEV;
+
+       /* Find Ethernet bearer for device (or create one) */
+
+       for (;(eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev); eb_ptr++);
+       if (eb_ptr == stop)
+               return -EDQUOT;
+       if (!eb_ptr->dev) {
+               eb_ptr->dev = dev;
+               eb_ptr->tipc_packet_type.type = __constant_htons(TIPC_PROTOCOL);
+               eb_ptr->tipc_packet_type.dev = dev;
+               eb_ptr->tipc_packet_type.func = recv_msg;
+               eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
+               INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
+               dev_hold(dev);
+               dev_add_pack(&eb_ptr->tipc_packet_type);
+       }
+
+       /* Associate TIPC bearer with Ethernet bearer */
+
+       eb_ptr->bearer = tb_ptr;
+       tb_ptr->usr_handle = (void *)eb_ptr;
+       tb_ptr->mtu = dev->mtu;
+       tb_ptr->blocked = 0; 
+       tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
+       memcpy(&tb_ptr->addr.dev_addr, &dev->dev_addr, ETH_ALEN);
+       return 0;
+}
+
+/**
+ * disable_bearer - detach TIPC bearer from an Ethernet interface 
+ *
+ * We really should do dev_remove_pack() here, but this function can not be
+ * called at tasklet level. => Use eth_bearer->bearer as a flag to throw away
+ * incoming buffers, & postpone dev_remove_pack() to eth_media_stop() on exit.
+ */
+
+static void disable_bearer(struct tipc_bearer *tb_ptr)
+{
+       ((struct eth_bearer *)tb_ptr->usr_handle)->bearer = 0;
+}
+
+/**
+ * recv_notification - handle device updates from OS
+ *
+ * Change the state of the Ethernet bearer (if any) associated with the 
+ * specified device.
+ */
+
+static int recv_notification(struct notifier_block *nb, unsigned long evt, 
+                            void *dv)
+{
+       struct net_device *dev = (struct net_device *)dv;
+       struct eth_bearer *eb_ptr = &eth_bearers[0];
+       struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
+
+       while ((eb_ptr->dev != dev)) {
+               if (++eb_ptr == stop)
+                       return NOTIFY_DONE;     /* couldn't find device */
+       }
+       if (!eb_ptr->bearer)
+               return NOTIFY_DONE;             /* bearer had been disabled */
+
+        eb_ptr->bearer->mtu = dev->mtu;
+
+       switch (evt) {
+       case NETDEV_CHANGE:
+               if (netif_carrier_ok(dev))
+                       tipc_continue(eb_ptr->bearer);
+               else
+                       tipc_block_bearer(eb_ptr->bearer->name);
+               break;
+       case NETDEV_UP:
+               tipc_continue(eb_ptr->bearer);
+               break;
+       case NETDEV_DOWN:
+               tipc_block_bearer(eb_ptr->bearer->name);
+               break;
+       case NETDEV_CHANGEMTU:
+        case NETDEV_CHANGEADDR:
+               tipc_block_bearer(eb_ptr->bearer->name);
+                tipc_continue(eb_ptr->bearer);
+               break;
+       case NETDEV_UNREGISTER:
+        case NETDEV_CHANGENAME:
+               tipc_disable_bearer(eb_ptr->bearer->name);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+/**
+ * eth_addr2str - convert Ethernet address to string
+ */
+
+static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
+{                       
+       unchar *addr = (unchar *)&a->dev_addr;
+
+       if (str_size < 18)
+               *str_buf = '\0';
+       else
+               sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+                       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+       return str_buf;
+}
+
+/**
+ * eth_media_start - activate Ethernet bearer support
+ *
+ * Register Ethernet media type with TIPC bearer code.  Also register
+ * with OS for notifications about device state changes.
+ */
+
+int eth_media_start(void)
+{                       
+       struct tipc_media_addr bcast_addr;
+       int res;
+
+       if (eth_started)
+               return -EINVAL;
+
+       memset(&bcast_addr, 0xff, sizeof(bcast_addr));
+       memset(eth_bearers, 0, sizeof(eth_bearers));
+
+       res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth",
+                                 enable_bearer, disable_bearer, send_msg, 
+                                 eth_addr2str, &bcast_addr, ETH_LINK_PRIORITY, 
+                                 ETH_LINK_TOLERANCE, TIPC_DEF_LINK_WIN);
+       if (res)
+               return res;
+
+       notifier.notifier_call = &recv_notification;
+       notifier.priority = 0;
+       res = register_netdevice_notifier(&notifier);
+       if (!res)
+               eth_started = 1;
+       return res;
+}
+
+/**
+ * eth_media_stop - deactivate Ethernet bearer support
+ */
+
+void eth_media_stop(void)
+{
+       int i;
+
+       if (!eth_started)
+               return;
+
+       unregister_netdevice_notifier(&notifier);
+       for (i = 0; i < MAX_ETH_BEARERS ; i++) {
+               if (eth_bearers[i].bearer) {
+                       eth_bearers[i].bearer->blocked = 1;
+                       eth_bearers[i].bearer = 0;
+               }
+               if (eth_bearers[i].dev) {
+                       dev_remove_pack(&eth_bearers[i].tipc_packet_type);
+                       dev_put(eth_bearers[i].dev);
+               }
+       }
+       memset(&eth_bearers, 0, sizeof(eth_bearers));
+       eth_started = 0;
+}
diff --git a/net/tipc/handler.c b/net/tipc/handler.c
new file mode 100644 (file)
index 0000000..f320010
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * net/tipc/handler.c: TIPC signal handling
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+struct queue_item {
+       struct list_head next_signal;
+       void (*handler) (unsigned long);
+       unsigned long data;
+};
+
+static kmem_cache_t *tipc_queue_item_cache;
+static struct list_head signal_queue_head;
+static spinlock_t qitem_lock = SPIN_LOCK_UNLOCKED;
+static int handler_enabled = 0;
+
+static void process_signal_queue(unsigned long dummy);
+
+static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0);
+
+
+unsigned int k_signal(Handler routine, unsigned long argument)
+{
+       struct queue_item *item;
+
+       if (!handler_enabled) {
+               err("Signal request ignored by handler\n");
+               return -ENOPROTOOPT;
+       }
+
+       spin_lock_bh(&qitem_lock);
+       item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
+       if (!item) {
+               err("Signal queue out of memory\n");
+               spin_unlock_bh(&qitem_lock);
+               return -ENOMEM;
+       }
+       item->handler = routine;
+       item->data = argument;
+       list_add_tail(&item->next_signal, &signal_queue_head);
+       spin_unlock_bh(&qitem_lock);
+       tasklet_schedule(&tipc_tasklet);
+       return 0;
+}
+
+static void process_signal_queue(unsigned long dummy)
+{
+       struct queue_item *__volatile__ item;
+       struct list_head *l, *n;
+
+       spin_lock_bh(&qitem_lock);
+       list_for_each_safe(l, n, &signal_queue_head) {
+               item = list_entry(l, struct queue_item, next_signal);
+               list_del(&item->next_signal);
+               spin_unlock_bh(&qitem_lock);
+               item->handler(item->data);
+               spin_lock_bh(&qitem_lock);
+               kmem_cache_free(tipc_queue_item_cache, item);
+       }
+       spin_unlock_bh(&qitem_lock);
+}
+
+int handler_start(void)
+{
+       tipc_queue_item_cache = 
+               kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
+                                 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+       if (!tipc_queue_item_cache)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&signal_queue_head);
+       tasklet_enable(&tipc_tasklet);
+       handler_enabled = 1;
+       return 0;
+}
+
+void handler_stop(void)
+{
+       struct list_head *l, *n;
+       struct queue_item *item; 
+
+       if (!handler_enabled)
+               return;
+
+       handler_enabled = 0;
+       tasklet_disable(&tipc_tasklet);
+       tasklet_kill(&tipc_tasklet);
+
+       spin_lock_bh(&qitem_lock);
+       list_for_each_safe(l, n, &signal_queue_head) {
+               item = list_entry(l, struct queue_item, next_signal);
+               list_del(&item->next_signal);
+               kmem_cache_free(tipc_queue_item_cache, item);
+       }
+       spin_unlock_bh(&qitem_lock);
+
+       kmem_cache_destroy(tipc_queue_item_cache);
+}
+
diff --git a/net/tipc/link.c b/net/tipc/link.c
new file mode 100644 (file)
index 0000000..7265f4b
--- /dev/null
@@ -0,0 +1,3167 @@
+/*
+ * net/tipc/link.c: TIPC link code
+ * 
+ * Copyright (c) 1996-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "link.h"
+#include "net.h"
+#include "node.h"
+#include "port.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "name_distr.h"
+#include "bearer.h"
+#include "name_table.h"
+#include "discover.h"
+#include "config.h"
+#include "bcast.h"
+
+
+/* 
+ * Limit for deferred reception queue: 
+ */
+
+#define DEF_QUEUE_LIMIT 256u
+
+/* 
+ * Link state events: 
+ */
+
+#define  STARTING_EVT    856384768     /* link processing trigger */
+#define  TRAFFIC_MSG_EVT 560815u       /* rx'd ??? */
+#define  TIMEOUT_EVT     560817u       /* link timer expired */
+
+/*   
+ * The following two 'message types' is really just implementation 
+ * data conveniently stored in the message header. 
+ * They must not be considered part of the protocol
+ */
+#define OPEN_MSG   0
+#define CLOSED_MSG 1
+
+/* 
+ * State value stored in 'exp_msg_count'
+ */
+
+#define START_CHANGEOVER 100000u
+
+/**
+ * struct link_name - deconstructed link name
+ * @addr_local: network address of node at this end
+ * @if_local: name of interface at this end
+ * @addr_peer: network address of node at far end
+ * @if_peer: name of interface at far end
+ */
+
+struct link_name {
+       u32 addr_local;
+       char if_local[TIPC_MAX_IF_NAME];
+       u32 addr_peer;
+       char if_peer[TIPC_MAX_IF_NAME];
+};
+
+#if 0
+
+/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
+
+/** 
+ * struct link_event - link up/down event notification
+ */
+
+struct link_event {
+       u32 addr;
+       int up;
+       void (*fcn)(u32, char *, int);
+       char name[TIPC_MAX_LINK_NAME];
+};
+
+#endif
+
+static void link_handle_out_of_seq_msg(struct link *l_ptr,
+                                      struct sk_buff *buf);
+static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf);
+static int  link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf);
+static void link_set_supervision_props(struct link *l_ptr, u32 tolerance);
+static int  link_send_sections_long(struct port *sender,
+                                   struct iovec const *msg_sect,
+                                   u32 num_sect, u32 destnode);
+static void link_check_defragm_bufs(struct link *l_ptr);
+static void link_state_event(struct link *l_ptr, u32 event);
+static void link_reset_statistics(struct link *l_ptr);
+static void link_print(struct link *l_ptr, struct print_buf *buf, 
+                      const char *str);
+
+/*
+ * Debugging code used by link routines only
+ *
+ * When debugging link problems on a system that has multiple links,
+ * the standard TIPC debugging routines may not be useful since they
+ * allow the output from multiple links to be intermixed.  For this reason
+ * routines of the form "dbg_link_XXX()" have been created that will capture
+ * debug info into a link's personal print buffer, which can then be dumped
+ * into the TIPC system log (LOG) upon request.
+ *
+ * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
+ * of the print buffer used by each link.  If LINK_LOG_BUF_SIZE is set to 0,
+ * the dbg_link_XXX() routines simply send their output to the standard 
+ * debug print buffer (DBG_OUTPUT), if it has been defined; this can be useful
+ * when there is only a single link in the system being debugged.
+ *
+ * Notes:
+ * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
+ * - "l_ptr" must be valid when using dbg_link_XXX() macros  
+ */
+
+#define LINK_LOG_BUF_SIZE 0
+
+#define dbg_link(fmt, arg...)  do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0)
+#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) msg_print(&l_ptr->print_buf, msg, txt); } while(0)
+#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0)
+#define dbg_link_dump() do { \
+       if (LINK_LOG_BUF_SIZE) { \
+               tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
+               printbuf_move(LOG, &l_ptr->print_buf); \
+       } \
+} while (0)
+
+static inline void dbg_print_link(struct link *l_ptr, const char *str)
+{
+       if (DBG_OUTPUT)
+               link_print(l_ptr, DBG_OUTPUT, str);
+}
+
+static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
+{
+       if (DBG_OUTPUT) {
+               struct sk_buff *buf = root_buf;
+
+               while (buf) {
+                       msg_dbg(buf_msg(buf), "In chain: ");
+                       buf = buf->next;
+               }
+       }
+}
+
+/*
+ *  Simple inlined link routines
+ */
+
+static inline unsigned int align(unsigned int i)
+{
+       return (i + 3) & ~3u;
+}
+
+static inline int link_working_working(struct link *l_ptr)
+{
+       return (l_ptr->state == WORKING_WORKING);
+}
+
+static inline int link_working_unknown(struct link *l_ptr)
+{
+       return (l_ptr->state == WORKING_UNKNOWN);
+}
+
+static inline int link_reset_unknown(struct link *l_ptr)
+{
+       return (l_ptr->state == RESET_UNKNOWN);
+}
+
+static inline int link_reset_reset(struct link *l_ptr)
+{
+       return (l_ptr->state == RESET_RESET);
+}
+
+static inline int link_blocked(struct link *l_ptr)
+{
+       return (l_ptr->exp_msg_count || l_ptr->blocked);
+}
+
+static inline int link_congested(struct link *l_ptr)
+{
+       return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
+}
+
+static inline u32 link_max_pkt(struct link *l_ptr)
+{
+       return l_ptr->max_pkt;
+}
+
+static inline void link_init_max_pkt(struct link *l_ptr)
+{
+       u32 max_pkt;
+       
+       max_pkt = (l_ptr->b_ptr->publ.mtu & ~3);
+       if (max_pkt > MAX_MSG_SIZE)
+               max_pkt = MAX_MSG_SIZE;
+
+        l_ptr->max_pkt_target = max_pkt;
+       if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
+               l_ptr->max_pkt = l_ptr->max_pkt_target;
+       else 
+               l_ptr->max_pkt = MAX_PKT_DEFAULT;
+
+        l_ptr->max_pkt_probes = 0;
+}
+
+static inline u32 link_next_sent(struct link *l_ptr)
+{
+       if (l_ptr->next_out)
+               return msg_seqno(buf_msg(l_ptr->next_out));
+       return mod(l_ptr->next_out_no);
+}
+
+static inline u32 link_last_sent(struct link *l_ptr)
+{
+       return mod(link_next_sent(l_ptr) - 1);
+}
+
+/*
+ *  Simple non-inlined link routines (i.e. referenced outside this file)
+ */
+
+int link_is_up(struct link *l_ptr)
+{
+       if (!l_ptr)
+               return 0;
+       return (link_working_working(l_ptr) || link_working_unknown(l_ptr));
+}
+
+int link_is_active(struct link *l_ptr)
+{
+       return ((l_ptr->owner->active_links[0] == l_ptr) ||
+               (l_ptr->owner->active_links[1] == l_ptr));
+}
+
+/**
+ * link_name_validate - validate & (optionally) deconstruct link name
+ * @name - ptr to link name string
+ * @name_parts - ptr to area for link name components (or NULL if not needed)
+ * 
+ * Returns 1 if link name is valid, otherwise 0.
+ */
+
+static int link_name_validate(const char *name, struct link_name *name_parts)
+{
+       char name_copy[TIPC_MAX_LINK_NAME];
+       char *addr_local;
+       char *if_local;
+       char *addr_peer;
+       char *if_peer;
+       char dummy;
+       u32 z_local, c_local, n_local;
+       u32 z_peer, c_peer, n_peer;
+       u32 if_local_len;
+       u32 if_peer_len;
+
+       /* copy link name & ensure length is OK */
+
+       name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
+       /* need above in case non-Posix strncpy() doesn't pad with nulls */
+       strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
+       if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
+               return 0;
+
+       /* ensure all component parts of link name are present */
+
+       addr_local = name_copy;
+       if ((if_local = strchr(addr_local, ':')) == NULL)
+               return 0;
+       *(if_local++) = 0;
+       if ((addr_peer = strchr(if_local, '-')) == NULL)
+               return 0;
+       *(addr_peer++) = 0;
+       if_local_len = addr_peer - if_local;
+       if ((if_peer = strchr(addr_peer, ':')) == NULL)
+               return 0;
+       *(if_peer++) = 0;
+       if_peer_len = strlen(if_peer) + 1;
+
+       /* validate component parts of link name */
+
+       if ((sscanf(addr_local, "%u.%u.%u%c",
+                   &z_local, &c_local, &n_local, &dummy) != 3) ||
+           (sscanf(addr_peer, "%u.%u.%u%c",
+                   &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
+           (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
+           (z_peer  > 255) || (c_peer  > 4095) || (n_peer  > 4095) ||
+           (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) || 
+           (if_peer_len  <= 1) || (if_peer_len  > TIPC_MAX_IF_NAME) || 
+           (strspn(if_local, tipc_alphabet) != (if_local_len - 1)) ||
+           (strspn(if_peer, tipc_alphabet) != (if_peer_len - 1)))
+               return 0;
+
+       /* return link name components, if necessary */
+
+       if (name_parts) {
+               name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
+               strcpy(name_parts->if_local, if_local);
+               name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
+               strcpy(name_parts->if_peer, if_peer);
+       }
+       return 1;
+}
+
+/**
+ * link_timeout - handle expiration of link timer
+ * @l_ptr: pointer to link
+ * 
+ * This routine must not grab "net_lock" to avoid a potential deadlock conflict
+ * with link_delete().  (There is no risk that the node will be deleted by
+ * another thread because link_delete() always cancels the link timer before
+ * node_delete() is called.)
+ */
+
+static void link_timeout(struct link *l_ptr)
+{
+       node_lock(l_ptr->owner);
+
+       /* update counters used in statistical profiling of send traffic */
+
+       l_ptr->stats.accu_queue_sz += l_ptr->out_queue_size;
+       l_ptr->stats.queue_sz_counts++;
+
+       if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz)
+               l_ptr->stats.max_queue_sz = l_ptr->out_queue_size;
+
+       if (l_ptr->first_out) {
+               struct tipc_msg *msg = buf_msg(l_ptr->first_out);
+               u32 length = msg_size(msg);
+
+               if ((msg_user(msg) == MSG_FRAGMENTER)
+                   && (msg_type(msg) == FIRST_FRAGMENT)) {
+                       length = msg_size(msg_get_wrapped(msg));
+               }
+               if (length) {
+                       l_ptr->stats.msg_lengths_total += length;
+                       l_ptr->stats.msg_length_counts++;
+                       if (length <= 64)
+                               l_ptr->stats.msg_length_profile[0]++;
+                       else if (length <= 256)
+                               l_ptr->stats.msg_length_profile[1]++;
+                       else if (length <= 1024)
+                               l_ptr->stats.msg_length_profile[2]++;
+                       else if (length <= 4096)
+                               l_ptr->stats.msg_length_profile[3]++;
+                       else if (length <= 16384)
+                               l_ptr->stats.msg_length_profile[4]++;
+                       else if (length <= 32768)
+                               l_ptr->stats.msg_length_profile[5]++;
+                       else
+                               l_ptr->stats.msg_length_profile[6]++;
+               }
+       }
+
+       /* do all other link processing performed on a periodic basis */
+
+       link_check_defragm_bufs(l_ptr);
+
+       link_state_event(l_ptr, TIMEOUT_EVT);
+
+       if (l_ptr->next_out)
+               link_push_queue(l_ptr);
+
+       node_unlock(l_ptr->owner);
+}
+
+static inline void link_set_timer(struct link *l_ptr, u32 time)
+{
+       k_start_timer(&l_ptr->timer, time);
+}
+
+/**
+ * link_create - create a new link
+ * @b_ptr: pointer to associated bearer
+ * @peer: network address of node at other end of link
+ * @media_addr: media address to use when sending messages over link
+ * 
+ * Returns pointer to link.
+ */
+
+struct link *link_create(struct bearer *b_ptr, const u32 peer,
+                        const struct tipc_media_addr *media_addr)
+{
+       struct link *l_ptr;
+       struct tipc_msg *msg;
+       char *if_name;
+
+       l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC);
+       if (!l_ptr) {
+               warn("Memory squeeze; Failed to create link\n");
+               return NULL;
+       }
+       memset(l_ptr, 0, sizeof(*l_ptr));
+
+       l_ptr->addr = peer;
+       if_name = strchr(b_ptr->publ.name, ':') + 1;
+       sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
+               tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
+               tipc_node(tipc_own_addr), 
+               if_name,
+               tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
+               /* note: peer i/f is appended to link name by reset/activate */
+       memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
+       k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
+       list_add_tail(&l_ptr->link_list, &b_ptr->links);
+       l_ptr->checkpoint = 1;
+       l_ptr->b_ptr = b_ptr;
+       link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
+       l_ptr->state = RESET_UNKNOWN;
+
+       l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
+       msg = l_ptr->pmsg;
+       msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+       msg_set_size(msg, sizeof(l_ptr->proto_msg));
+       msg_set_session(msg, tipc_random);
+       msg_set_bearer_id(msg, b_ptr->identity);
+       strcpy((char *)msg_data(msg), if_name);
+
+       l_ptr->priority = b_ptr->priority;
+       link_set_queue_limits(l_ptr, b_ptr->media->window);
+
+       link_init_max_pkt(l_ptr);
+
+       l_ptr->next_out_no = 1;
+       INIT_LIST_HEAD(&l_ptr->waiting_ports);
+
+       link_reset_statistics(l_ptr);
+
+       l_ptr->owner = node_attach_link(l_ptr);
+       if (!l_ptr->owner) {
+               kfree(l_ptr);
+               return NULL;
+       }
+
+       if (LINK_LOG_BUF_SIZE) {
+               char *pb = kmalloc(LINK_LOG_BUF_SIZE, GFP_ATOMIC);
+
+               if (!pb) {
+                       kfree(l_ptr);
+                       warn("Memory squeeze; Failed to create link\n");
+                       return NULL;
+               }
+               printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
+       }
+
+       k_signal((Handler)link_start, (unsigned long)l_ptr);
+
+       dbg("link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n",
+           l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit);
+       
+       return l_ptr;
+}
+
+/** 
+ * link_delete - delete a link
+ * @l_ptr: pointer to link
+ * 
+ * Note: 'net_lock' is write_locked, bearer is locked.
+ * This routine must not grab the node lock until after link timer cancellation
+ * to avoid a potential deadlock situation.  
+ */
+
+void link_delete(struct link *l_ptr)
+{
+       if (!l_ptr) {
+               err("Attempt to delete non-existent link\n");
+               return;
+       }
+
+       dbg("link_delete()\n");
+
+       k_cancel_timer(&l_ptr->timer);
+       
+       node_lock(l_ptr->owner);
+       link_reset(l_ptr);
+       node_detach_link(l_ptr->owner, l_ptr);
+       link_stop(l_ptr);
+       list_del_init(&l_ptr->link_list);
+       if (LINK_LOG_BUF_SIZE)
+               kfree(l_ptr->print_buf.buf);
+       node_unlock(l_ptr->owner);
+       k_term_timer(&l_ptr->timer);
+       kfree(l_ptr);
+}
+
+void link_start(struct link *l_ptr)
+{
+       dbg("link_start %x\n", l_ptr);
+       link_state_event(l_ptr, STARTING_EVT);
+}
+
+/**
+ * link_schedule_port - schedule port for deferred sending 
+ * @l_ptr: pointer to link
+ * @origport: reference to sending port
+ * @sz: amount of data to be sent
+ * 
+ * Schedules port for renewed sending of messages after link congestion 
+ * has abated.
+ */
+
+static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz)
+{
+       struct port *p_ptr;
+
+       spin_lock_bh(&port_list_lock);
+       p_ptr = port_lock(origport);
+       if (p_ptr) {
+               if (!p_ptr->wakeup)
+                       goto exit;
+               if (!list_empty(&p_ptr->wait_list))
+                       goto exit;
+               p_ptr->congested_link = l_ptr;
+               p_ptr->publ.congested = 1;
+               p_ptr->waiting_pkts = 1 + ((sz - 1) / link_max_pkt(l_ptr));
+               list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
+               l_ptr->stats.link_congs++;
+exit:
+               port_unlock(p_ptr);
+       }
+       spin_unlock_bh(&port_list_lock);
+       return -ELINKCONG;
+}
+
+void link_wakeup_ports(struct link *l_ptr, int all)
+{
+       struct port *p_ptr;
+       struct port *temp_p_ptr;
+       int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
+
+       if (all)
+               win = 100000;
+       if (win <= 0)
+               return;
+       if (!spin_trylock_bh(&port_list_lock))
+               return;
+       if (link_congested(l_ptr))
+               goto exit;
+       list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports, 
+                                wait_list) {
+               if (win <= 0)
+                       break;
+               list_del_init(&p_ptr->wait_list);
+               p_ptr->congested_link = 0;
+               assert(p_ptr->wakeup);
+               spin_lock_bh(p_ptr->publ.lock);
+               p_ptr->publ.congested = 0;
+               p_ptr->wakeup(&p_ptr->publ);
+               win -= p_ptr->waiting_pkts;
+               spin_unlock_bh(p_ptr->publ.lock);
+       }
+
+exit:
+       spin_unlock_bh(&port_list_lock);
+}
+
+/** 
+ * link_release_outqueue - purge link's outbound message queue
+ * @l_ptr: pointer to link
+ */
+
+static void link_release_outqueue(struct link *l_ptr)
+{
+       struct sk_buff *buf = l_ptr->first_out;
+       struct sk_buff *next;
+
+       while (buf) {
+               next = buf->next;
+               buf_discard(buf);
+               buf = next;
+       }
+       l_ptr->first_out = NULL;
+       l_ptr->out_queue_size = 0;
+}
+
+/**
+ * link_reset_fragments - purge link's inbound message fragments queue
+ * @l_ptr: pointer to link
+ */
+
+void link_reset_fragments(struct link *l_ptr)
+{
+       struct sk_buff *buf = l_ptr->defragm_buf;
+       struct sk_buff *next;
+
+       while (buf) {
+               next = buf->next;
+               buf_discard(buf);
+               buf = next;
+       }
+       l_ptr->defragm_buf = NULL;
+}
+
+/** 
+ * link_stop - purge all inbound and outbound messages associated with link
+ * @l_ptr: pointer to link
+ */
+
+void link_stop(struct link *l_ptr)
+{
+       struct sk_buff *buf;
+       struct sk_buff *next;
+
+       buf = l_ptr->oldest_deferred_in;
+       while (buf) {
+               next = buf->next;
+               buf_discard(buf);
+               buf = next;
+       }
+
+       buf = l_ptr->first_out;
+       while (buf) {
+               next = buf->next;
+               buf_discard(buf);
+               buf = next;
+       }
+
+       link_reset_fragments(l_ptr);
+
+       buf_discard(l_ptr->proto_msg_queue);
+       l_ptr->proto_msg_queue = NULL;
+}
+
+#if 0
+
+/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
+
+static void link_recv_event(struct link_event *ev)
+{
+       ev->fcn(ev->addr, ev->name, ev->up);
+       kfree(ev);
+}
+
+static void link_send_event(void (*fcn)(u32 a, char *n, int up),
+                           struct link *l_ptr, int up)
+{
+       struct link_event *ev;
+       
+       ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+       if (!ev) {
+               warn("Link event allocation failure\n");
+               return;
+       }
+       ev->addr = l_ptr->addr;
+       ev->up = up;
+       ev->fcn = fcn;
+       memcpy(ev->name, l_ptr->name, TIPC_MAX_LINK_NAME);
+       k_signal((Handler)link_recv_event, (unsigned long)ev);
+}
+
+#else
+
+#define link_send_event(fcn, l_ptr, up) do { } while (0)
+
+#endif
+
+void link_reset(struct link *l_ptr)
+{
+       struct sk_buff *buf;
+       u32 prev_state = l_ptr->state;
+       u32 checkpoint = l_ptr->next_in_no;
+       
+       msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
+
+        /* Link is down, accept any session: */
+       l_ptr->peer_session = 0;
+
+        /* Prepare for max packet size negotiation */
+       link_init_max_pkt(l_ptr);
+       
+       l_ptr->state = RESET_UNKNOWN;
+       dbg_link_state("Resetting Link\n");
+
+       if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
+               return;
+
+       node_link_down(l_ptr->owner, l_ptr);
+       bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
+#if 0
+       tipc_printf(CONS, "\nReset link <%s>\n", l_ptr->name);
+       dbg_link_dump();
+#endif
+       if (node_has_active_links(l_ptr->owner) &&
+           l_ptr->owner->permit_changeover) {
+               l_ptr->reset_checkpoint = checkpoint;
+               l_ptr->exp_msg_count = START_CHANGEOVER;
+       }
+
+       /* Clean up all queues: */
+
+       link_release_outqueue(l_ptr);
+       buf_discard(l_ptr->proto_msg_queue);
+       l_ptr->proto_msg_queue = NULL;
+       buf = l_ptr->oldest_deferred_in;
+       while (buf) {
+               struct sk_buff *next = buf->next;
+               buf_discard(buf);
+               buf = next;
+       }
+       if (!list_empty(&l_ptr->waiting_ports))
+               link_wakeup_ports(l_ptr, 1);
+
+       l_ptr->retransm_queue_head = 0;
+       l_ptr->retransm_queue_size = 0;
+       l_ptr->last_out = NULL;
+       l_ptr->first_out = NULL;
+       l_ptr->next_out = NULL;
+       l_ptr->unacked_window = 0;
+       l_ptr->checkpoint = 1;
+       l_ptr->next_out_no = 1;
+       l_ptr->deferred_inqueue_sz = 0;
+       l_ptr->oldest_deferred_in = NULL;
+       l_ptr->newest_deferred_in = NULL;
+       l_ptr->fsm_msg_cnt = 0;
+       l_ptr->stale_count = 0;
+       link_reset_statistics(l_ptr);
+
+       link_send_event(cfg_link_event, l_ptr, 0);
+       if (!in_own_cluster(l_ptr->addr))
+               link_send_event(disc_link_event, l_ptr, 0);
+}
+
+
+static void link_activate(struct link *l_ptr)
+{
+       l_ptr->next_in_no = 1;
+       node_link_up(l_ptr->owner, l_ptr);
+       bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
+       link_send_event(cfg_link_event, l_ptr, 1);
+       if (!in_own_cluster(l_ptr->addr))
+               link_send_event(disc_link_event, l_ptr, 1);
+}
+
+/**
+ * link_state_event - link finite state machine
+ * @l_ptr: pointer to link
+ * @event: state machine event to process
+ */
+
+static void link_state_event(struct link *l_ptr, unsigned event)
+{
+       struct link *other; 
+       u32 cont_intv = l_ptr->continuity_interval;
+
+       if (!l_ptr->started && (event != STARTING_EVT))
+               return;         /* Not yet. */
+
+       if (link_blocked(l_ptr)) {
+               if (event == TIMEOUT_EVT) {
+                       link_set_timer(l_ptr, cont_intv);
+               }
+               return;   /* Changeover going on */
+       }
+       dbg_link("STATE_EV: <%s> ", l_ptr->name);
+
+       switch (l_ptr->state) {
+       case WORKING_WORKING:
+               dbg_link("WW/");
+               switch (event) {
+               case TRAFFIC_MSG_EVT:
+                       dbg_link("TRF-");
+                       /* fall through */
+               case ACTIVATE_MSG:
+                       dbg_link("ACT\n");
+                       break;
+               case TIMEOUT_EVT:
+                       dbg_link("TIM ");
+                       if (l_ptr->next_in_no != l_ptr->checkpoint) {
+                               l_ptr->checkpoint = l_ptr->next_in_no;
+                               if (bclink_acks_missing(l_ptr->owner)) {
+                                       link_send_proto_msg(l_ptr, STATE_MSG, 
+                                                           0, 0, 0, 0, 0);
+                                       l_ptr->fsm_msg_cnt++;
+                               } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
+                                       link_send_proto_msg(l_ptr, STATE_MSG, 
+                                                           1, 0, 0, 0, 0);
+                                       l_ptr->fsm_msg_cnt++;
+                               }
+                               link_set_timer(l_ptr, cont_intv);
+                               break;
+                       }
+                       dbg_link(" -> WU\n");
+                       l_ptr->state = WORKING_UNKNOWN;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv / 4);
+                       break;
+               case RESET_MSG:
+                       dbg_link("RES -> RR\n");
+                       link_reset(l_ptr);
+                       l_ptr->state = RESET_RESET;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               default:
+                       err("Unknown link event %u in WW state\n", event);
+               }
+               break;
+       case WORKING_UNKNOWN:
+               dbg_link("WU/");
+               switch (event) {
+               case TRAFFIC_MSG_EVT:
+                       dbg_link("TRF-");
+               case ACTIVATE_MSG:
+                       dbg_link("ACT -> WW\n");
+                       l_ptr->state = WORKING_WORKING;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               case RESET_MSG:
+                       dbg_link("RES -> RR\n");
+                       link_reset(l_ptr);
+                       l_ptr->state = RESET_RESET;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               case TIMEOUT_EVT:
+                       dbg_link("TIM ");
+                       if (l_ptr->next_in_no != l_ptr->checkpoint) {
+                               dbg_link("-> WW \n");
+                               l_ptr->state = WORKING_WORKING;
+                               l_ptr->fsm_msg_cnt = 0;
+                               l_ptr->checkpoint = l_ptr->next_in_no;
+                               if (bclink_acks_missing(l_ptr->owner)) {
+                                       link_send_proto_msg(l_ptr, STATE_MSG,
+                                                           0, 0, 0, 0, 0);
+                                       l_ptr->fsm_msg_cnt++;
+                               }
+                               link_set_timer(l_ptr, cont_intv);
+                       } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
+                               dbg_link("Probing %u/%u,timer = %u ms)\n",
+                                        l_ptr->fsm_msg_cnt, l_ptr->abort_limit,
+                                        cont_intv / 4);
+                               link_send_proto_msg(l_ptr, STATE_MSG, 
+                                                   1, 0, 0, 0, 0);
+                               l_ptr->fsm_msg_cnt++;
+                               link_set_timer(l_ptr, cont_intv / 4);
+                       } else {        /* Link has failed */
+                               dbg_link("-> RU (%u probes unanswered)\n",
+                                        l_ptr->fsm_msg_cnt);
+                               link_reset(l_ptr);
+                               l_ptr->state = RESET_UNKNOWN;
+                               l_ptr->fsm_msg_cnt = 0;
+                               link_send_proto_msg(l_ptr, RESET_MSG,
+                                                   0, 0, 0, 0, 0);
+                               l_ptr->fsm_msg_cnt++;
+                               link_set_timer(l_ptr, cont_intv);
+                       }
+                       break;
+               default:
+                       err("Unknown link event %u in WU state\n", event);
+               }
+               break;
+       case RESET_UNKNOWN:
+               dbg_link("RU/");
+               switch (event) {
+               case TRAFFIC_MSG_EVT:
+                       dbg_link("TRF-\n");
+                       break;
+               case ACTIVATE_MSG:
+                       other = l_ptr->owner->active_links[0];
+                       if (other && link_working_unknown(other)) {
+                               dbg_link("ACT\n");
+                               break;
+                       }
+                       dbg_link("ACT -> WW\n");
+                       l_ptr->state = WORKING_WORKING;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_activate(l_ptr);
+                       link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               case RESET_MSG:
+                       dbg_link("RES \n");
+                       dbg_link(" -> RR\n");
+                       l_ptr->state = RESET_RESET;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               case STARTING_EVT:
+                       dbg_link("START-");
+                       l_ptr->started = 1;
+                       /* fall through */
+               case TIMEOUT_EVT:
+                       dbg_link("TIM \n");
+                       link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               default:
+                       err("Unknown link event %u in RU state\n", event);
+               }
+               break;
+       case RESET_RESET:
+               dbg_link("RR/ ");
+               switch (event) {
+               case TRAFFIC_MSG_EVT:
+                       dbg_link("TRF-");
+                       /* fall through */
+               case ACTIVATE_MSG:
+                       other = l_ptr->owner->active_links[0];
+                       if (other && link_working_unknown(other)) {
+                               dbg_link("ACT\n");
+                               break;
+                       }
+                       dbg_link("ACT -> WW\n");
+                       l_ptr->state = WORKING_WORKING;
+                       l_ptr->fsm_msg_cnt = 0;
+                       link_activate(l_ptr);
+                       link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       break;
+               case RESET_MSG:
+                       dbg_link("RES\n");
+                       break;
+               case TIMEOUT_EVT:
+                       dbg_link("TIM\n");
+                       link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+                       l_ptr->fsm_msg_cnt++;
+                       link_set_timer(l_ptr, cont_intv);
+                       dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt);
+                       break;
+               default:
+                       err("Unknown link event %u in RR state\n", event);
+               }
+               break;
+       default:
+               err("Unknown link state %u/%u\n", l_ptr->state, event);
+       }
+}
+
+/*
+ * link_bundle_buf(): Append contents of a buffer to
+ * the tail of an existing one. 
+ */
+
+static int link_bundle_buf(struct link *l_ptr,
+                          struct sk_buff *bundler, 
+                          struct sk_buff *buf)
+{
+       struct tipc_msg *bundler_msg = buf_msg(bundler);
+       struct tipc_msg *msg = buf_msg(buf);
+       u32 size = msg_size(msg);
+       u32 to_pos = align(msg_size(bundler_msg));
+       u32 rest = link_max_pkt(l_ptr) - to_pos;
+
+       if (msg_user(bundler_msg) != MSG_BUNDLER)
+               return 0;
+       if (msg_type(bundler_msg) != OPEN_MSG)
+               return 0;
+       if (rest < align(size))
+               return 0;
+
+       skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size);
+       memcpy(bundler->data + to_pos, buf->data, size);
+       msg_set_size(bundler_msg, to_pos + size);
+       msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
+       dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n",
+           msg_msgcnt(bundler_msg), size, to_pos, msg_seqno(bundler_msg));
+       msg_dbg(msg, "PACKD:");
+       buf_discard(buf);
+       l_ptr->stats.sent_bundled++;
+       return 1;
+}
+
+static inline void link_add_to_outqueue(struct link *l_ptr, 
+                                       struct sk_buff *buf, 
+                                       struct tipc_msg *msg)
+{
+       u32 ack = mod(l_ptr->next_in_no - 1);
+       u32 seqno = mod(l_ptr->next_out_no++);
+
+       msg_set_word(msg, 2, ((ack << 16) | seqno));
+       msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
+       buf->next = NULL;
+       if (l_ptr->first_out) {
+               l_ptr->last_out->next = buf;
+               l_ptr->last_out = buf;
+       } else
+               l_ptr->first_out = l_ptr->last_out = buf;
+       l_ptr->out_queue_size++;
+}
+
+/* 
+ * link_send_buf() is the 'full path' for messages, called from 
+ * inside TIPC when the 'fast path' in tipc_send_buf
+ * has failed, and from link_send()
+ */
+
+int link_send_buf(struct link *l_ptr, struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       u32 size = msg_size(msg);
+       u32 dsz = msg_data_sz(msg);
+       u32 queue_size = l_ptr->out_queue_size;
+       u32 imp = msg_tot_importance(msg);
+       u32 queue_limit = l_ptr->queue_limit[imp];
+       u32 max_packet = link_max_pkt(l_ptr);
+
+       msg_set_prevnode(msg, tipc_own_addr);   /* If routed message */
+
+       /* Match msg importance against queue limits: */
+
+       if (unlikely(queue_size >= queue_limit)) {
+               if (imp <= TIPC_CRITICAL_IMPORTANCE) {
+                       return link_schedule_port(l_ptr, msg_origport(msg),
+                                                 size);
+               }
+               msg_dbg(msg, "TIPC: Congestion, throwing away\n");
+               buf_discard(buf);
+               if (imp > CONN_MANAGER) {
+                       warn("Resetting <%s>, send queue full", l_ptr->name);
+                       link_reset(l_ptr);
+               }
+               return dsz;
+       }
+
+       /* Fragmentation needed ? */
+
+       if (size > max_packet)
+               return link_send_long_buf(l_ptr, buf);
+
+       /* Packet can be queued or sent: */
+
+       if (queue_size > l_ptr->stats.max_queue_sz)
+               l_ptr->stats.max_queue_sz = queue_size;
+
+       if (likely(!bearer_congested(l_ptr->b_ptr, l_ptr) && 
+                  !link_congested(l_ptr))) {
+               link_add_to_outqueue(l_ptr, buf, msg);
+
+               if (likely(bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr))) {
+                       l_ptr->unacked_window = 0;
+               } else {
+                       bearer_schedule(l_ptr->b_ptr, l_ptr);
+                       l_ptr->stats.bearer_congs++;
+                       l_ptr->next_out = buf;
+               }
+               return dsz;
+       }
+       /* Congestion: can message be bundled ?: */
+
+       if ((msg_user(msg) != CHANGEOVER_PROTOCOL) &&
+           (msg_user(msg) != MSG_FRAGMENTER)) {
+
+               /* Try adding message to an existing bundle */
+
+               if (l_ptr->next_out && 
+                   link_bundle_buf(l_ptr, l_ptr->last_out, buf)) {
+                       bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
+                       return dsz;
+               }
+
+               /* Try creating a new bundle */
+
+               if (size <= max_packet * 2 / 3) {
+                       struct sk_buff *bundler = buf_acquire(max_packet);
+                       struct tipc_msg bundler_hdr;
+
+                       if (bundler) {
+                               msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
+                                        TIPC_OK, INT_H_SIZE, l_ptr->addr);
+                               memcpy(bundler->data, (unchar *)&bundler_hdr, 
+                                      INT_H_SIZE);
+                               skb_trim(bundler, INT_H_SIZE);
+                               link_bundle_buf(l_ptr, bundler, buf);
+                               buf = bundler;
+                               msg = buf_msg(buf);
+                               l_ptr->stats.sent_bundles++;
+                       }
+               }
+       }
+       if (!l_ptr->next_out)
+               l_ptr->next_out = buf;
+       link_add_to_outqueue(l_ptr, buf, msg);
+       bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
+       return dsz;
+}
+
+/* 
+ * link_send(): same as link_send_buf(), but the link to use has 
+ * not been selected yet, and the the owner node is not locked
+ * Called by TIPC internal users, e.g. the name distributor
+ */
+
+int link_send(struct sk_buff *buf, u32 dest, u32 selector)
+{
+       struct link *l_ptr;
+       struct node *n_ptr;
+       int res = -ELINKCONG;
+
+       read_lock_bh(&net_lock);
+       n_ptr = node_select(dest, selector);
+       if (n_ptr) {
+               node_lock(n_ptr);
+               l_ptr = n_ptr->active_links[selector & 1];
+               dbg("link_send: found link %x for dest %x\n", l_ptr, dest);
+               if (l_ptr) {
+                       res = link_send_buf(l_ptr, buf);
+               }
+               node_unlock(n_ptr);
+       } else {
+               dbg("Attempt to send msg to unknown node:\n");
+               msg_dbg(buf_msg(buf),">>>");
+               buf_discard(buf);
+       }
+       read_unlock_bh(&net_lock);
+       return res;
+}
+
+/* 
+ * link_send_buf_fast: Entry for data messages where the 
+ * destination link is known and the header is complete,
+ * inclusive total message length. Very time critical.
+ * Link is locked. Returns user data length.
+ */
+
+static inline int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
+                                    u32 *used_max_pkt)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       int res = msg_data_sz(msg);
+
+       if (likely(!link_congested(l_ptr))) {
+               if (likely(msg_size(msg) <= link_max_pkt(l_ptr))) {
+                       if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
+                               link_add_to_outqueue(l_ptr, buf, msg);
+                               if (likely(bearer_send(l_ptr->b_ptr, buf,
+                                                      &l_ptr->media_addr))) {
+                                       l_ptr->unacked_window = 0;
+                                       msg_dbg(msg,"SENT_FAST:");
+                                       return res;
+                               }
+                               dbg("failed sent fast...\n");
+                               bearer_schedule(l_ptr->b_ptr, l_ptr);
+                               l_ptr->stats.bearer_congs++;
+                               l_ptr->next_out = buf;
+                               return res;
+                       }
+               }
+               else
+                       *used_max_pkt = link_max_pkt(l_ptr);
+       }
+       return link_send_buf(l_ptr, buf);  /* All other cases */
+}
+
+/* 
+ * tipc_send_buf_fast: Entry for data messages where the 
+ * destination node is known and the header is complete,
+ * inclusive total message length.
+ * Returns user data length.
+ */
+int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
+{
+       struct link *l_ptr;
+       struct node *n_ptr;
+       int res;
+       u32 selector = msg_origport(buf_msg(buf)) & 1;
+       u32 dummy;
+
+       if (destnode == tipc_own_addr)
+               return port_recv_msg(buf);
+
+       read_lock_bh(&net_lock);
+       n_ptr = node_select(destnode, selector);
+       if (likely(n_ptr)) {
+               node_lock(n_ptr);
+               l_ptr = n_ptr->active_links[selector];
+               dbg("send_fast: buf %x selected %x, destnode = %x\n",
+                   buf, l_ptr, destnode);
+               if (likely(l_ptr)) {
+                       res = link_send_buf_fast(l_ptr, buf, &dummy);
+                       node_unlock(n_ptr);
+                       read_unlock_bh(&net_lock);
+                       return res;
+               }
+               node_unlock(n_ptr);
+       }
+       read_unlock_bh(&net_lock);
+       res = msg_data_sz(buf_msg(buf));
+       tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
+       return res;
+}
+
+
+/* 
+ * link_send_sections_fast: Entry for messages where the 
+ * destination processor is known and the header is complete,
+ * except for total message length. 
+ * Returns user data length or errno.
+ */
+int link_send_sections_fast(struct port *sender, 
+                           struct iovec const *msg_sect,
+                           const u32 num_sect, 
+                           u32 destaddr)
+{
+       struct tipc_msg *hdr = &sender->publ.phdr;
+       struct link *l_ptr;
+       struct sk_buff *buf;
+       struct node *node;
+       int res;
+       u32 selector = msg_origport(hdr) & 1;
+
+       assert(destaddr != tipc_own_addr);
+
+again:
+       /*
+        * Try building message using port's max_pkt hint.
+        * (Must not hold any locks while building message.)
+        */
+
+       res = msg_build(hdr, msg_sect, num_sect, sender->max_pkt,
+                       !sender->user_port, &buf);
+
+       read_lock_bh(&net_lock);
+       node = node_select(destaddr, selector);
+       if (likely(node)) {
+               node_lock(node);
+               l_ptr = node->active_links[selector];
+               if (likely(l_ptr)) {
+                       if (likely(buf)) {
+                               res = link_send_buf_fast(l_ptr, buf,
+                                                        &sender->max_pkt);
+                               if (unlikely(res < 0))
+                                       buf_discard(buf);
+exit:
+                               node_unlock(node);
+                               read_unlock_bh(&net_lock);
+                               return res;
+                       }
+
+                       /* Exit if build request was invalid */
+
+                       if (unlikely(res < 0))
+                               goto exit;
+
+                       /* Exit if link (or bearer) is congested */
+
+                       if (link_congested(l_ptr) || 
+                           !list_empty(&l_ptr->b_ptr->cong_links)) {
+                               res = link_schedule_port(l_ptr,
+                                                        sender->publ.ref, res);
+                               goto exit;
+                       }
+
+                       /* 
+                        * Message size exceeds max_pkt hint; update hint,
+                        * then re-try fast path or fragment the message
+                        */
+
+                       sender->max_pkt = link_max_pkt(l_ptr);
+                       node_unlock(node);
+                       read_unlock_bh(&net_lock);
+
+
+                       if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
+                               goto again;
+
+                       return link_send_sections_long(sender, msg_sect,
+                                                      num_sect, destaddr);
+               }
+               node_unlock(node);
+       }
+       read_unlock_bh(&net_lock);
+
+       /* Couldn't find a link to the destination node */
+
+       if (buf)
+               return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
+       if (res >= 0)
+               return port_reject_sections(sender, hdr, msg_sect, num_sect,
+                                           TIPC_ERR_NO_NODE);
+       return res;
+}
+
+/* 
+ * link_send_sections_long(): Entry for long messages where the 
+ * destination node is known and the header is complete,
+ * inclusive total message length. 
+ * Link and bearer congestion status have been checked to be ok,
+ * and are ignored if they change.
+ *
+ * Note that fragments do not use the full link MTU so that they won't have
+ * to undergo refragmentation if link changeover causes them to be sent
+ * over another link with an additional tunnel header added as prefix.
+ * (Refragmentation will still occur if the other link has a smaller MTU.)
+ *
+ * Returns user data length or errno.
+ */
+static int link_send_sections_long(struct port *sender,
+                                  struct iovec const *msg_sect,
+                                  u32 num_sect,
+                                  u32 destaddr)
+{
+       struct link *l_ptr;
+       struct node *node;
+       struct tipc_msg *hdr = &sender->publ.phdr;
+       u32 dsz = msg_data_sz(hdr);
+       u32 max_pkt,fragm_sz,rest;
+       struct tipc_msg fragm_hdr;
+       struct sk_buff *buf,*buf_chain,*prev;
+       u32 fragm_crs,fragm_rest,hsz,sect_rest;
+       const unchar *sect_crs;
+       int curr_sect;
+       u32 fragm_no;
+
+again:
+       fragm_no = 1;
+       max_pkt = sender->max_pkt - INT_H_SIZE;  
+               /* leave room for tunnel header in case of link changeover */
+       fragm_sz = max_pkt - INT_H_SIZE; 
+               /* leave room for fragmentation header in each fragment */
+       rest = dsz;
+       fragm_crs = 0;
+       fragm_rest = 0;
+       sect_rest = 0;
+       sect_crs = 0;
+       curr_sect = -1;
+
+       /* Prepare reusable fragment header: */
+
+       msg_dbg(hdr, ">FRAGMENTING>");
+       msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
+                TIPC_OK, INT_H_SIZE, msg_destnode(hdr));
+       msg_set_link_selector(&fragm_hdr, sender->publ.ref);
+       msg_set_size(&fragm_hdr, max_pkt);
+       msg_set_fragm_no(&fragm_hdr, 1);
+
+       /* Prepare header of first fragment: */
+
+       buf_chain = buf = buf_acquire(max_pkt);
+       if (!buf)
+               return -ENOMEM;
+       buf->next = NULL;
+       memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+       hsz = msg_hdr_sz(hdr);
+       memcpy(buf->data + INT_H_SIZE, (unchar *)hdr, hsz);
+       msg_dbg(buf_msg(buf), ">BUILD>");
+
+       /* Chop up message: */
+
+       fragm_crs = INT_H_SIZE + hsz;
+       fragm_rest = fragm_sz - hsz;
+
+       do {            /* For all sections */
+               u32 sz;
+
+               if (!sect_rest) {
+                       sect_rest = msg_sect[++curr_sect].iov_len;
+                       sect_crs = (const unchar *)msg_sect[curr_sect].iov_base;
+               }
+
+               if (sect_rest < fragm_rest)
+                       sz = sect_rest;
+               else
+                       sz = fragm_rest;
+
+               if (likely(!sender->user_port)) {
+                       if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) {
+error:
+                               for (; buf_chain; buf_chain = buf) {
+                                       buf = buf_chain->next;
+                                       buf_discard(buf_chain);
+                               }
+                               return -EFAULT;
+                       }
+               } else
+                       memcpy(buf->data + fragm_crs, sect_crs, sz);
+
+               sect_crs += sz;
+               sect_rest -= sz;
+               fragm_crs += sz;
+               fragm_rest -= sz;
+               rest -= sz;
+
+               if (!fragm_rest && rest) {
+
+                       /* Initiate new fragment: */
+                       if (rest <= fragm_sz) {
+                               fragm_sz = rest;
+                               msg_set_type(&fragm_hdr,LAST_FRAGMENT);
+                       } else {
+                               msg_set_type(&fragm_hdr, FRAGMENT);
+                       }
+                       msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
+                       msg_set_fragm_no(&fragm_hdr, ++fragm_no);
+                       prev = buf;
+                       buf = buf_acquire(fragm_sz + INT_H_SIZE);
+                       if (!buf)
+                               goto error;
+
+                       buf->next = NULL;                                
+                       prev->next = buf;
+                       memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+                       fragm_crs = INT_H_SIZE;
+                       fragm_rest = fragm_sz;
+                       msg_dbg(buf_msg(buf),"  >BUILD>");
+               }
+       }
+       while (rest > 0);
+
+       /* 
+        * Now we have a buffer chain. Select a link and check
+        * that packet size is still OK
+        */
+       node = node_select(destaddr, sender->publ.ref & 1);
+       if (likely(node)) {
+               node_lock(node);
+               l_ptr = node->active_links[sender->publ.ref & 1];
+               if (!l_ptr) {
+                       node_unlock(node);
+                       goto reject;
+               }
+               if (link_max_pkt(l_ptr) < max_pkt) {
+                       sender->max_pkt = link_max_pkt(l_ptr);
+                       node_unlock(node);
+                       for (; buf_chain; buf_chain = buf) {
+                               buf = buf_chain->next;
+                               buf_discard(buf_chain);
+                       }
+                       goto again;
+               }
+       } else {
+reject:
+               for (; buf_chain; buf_chain = buf) {
+                       buf = buf_chain->next;
+                       buf_discard(buf_chain);
+               }
+               return port_reject_sections(sender, hdr, msg_sect, num_sect,
+                                           TIPC_ERR_NO_NODE);
+       }
+
+       /* Append whole chain to send queue: */
+
+       buf = buf_chain;
+       l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1);
+       if (!l_ptr->next_out)
+               l_ptr->next_out = buf_chain;
+       l_ptr->stats.sent_fragmented++;
+       while (buf) {
+               struct sk_buff *next = buf->next;
+               struct tipc_msg *msg = buf_msg(buf);
+
+               l_ptr->stats.sent_fragments++;
+               msg_set_long_msgno(msg, l_ptr->long_msg_seq_no);
+               link_add_to_outqueue(l_ptr, buf, msg);
+               msg_dbg(msg, ">ADD>");
+               buf = next;
+       }
+
+       /* Send it, if possible: */
+
+       link_push_queue(l_ptr);
+       node_unlock(node);
+       return dsz;
+}
+
+/* 
+ * link_push_packet: Push one unsent packet to the media
+ */
+u32 link_push_packet(struct link *l_ptr)
+{
+       struct sk_buff *buf = l_ptr->first_out;
+       u32 r_q_size = l_ptr->retransm_queue_size;
+       u32 r_q_head = l_ptr->retransm_queue_head;
+
+       /* Step to position where retransmission failed, if any,    */
+       /* consider that buffers may have been released in meantime */
+
+       if (r_q_size && buf) {
+               u32 last = lesser(mod(r_q_head + r_q_size), 
+                                 link_last_sent(l_ptr));
+               u32 first = msg_seqno(buf_msg(buf));
+
+               while (buf && less(first, r_q_head)) {
+                       first = mod(first + 1);
+                       buf = buf->next;
+               }
+               l_ptr->retransm_queue_head = r_q_head = first;
+               l_ptr->retransm_queue_size = r_q_size = mod(last - first);
+       }
+
+       /* Continue retransmission now, if there is anything: */
+
+       if (r_q_size && buf && !skb_cloned(buf)) {
+               msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
+               msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in); 
+               if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+                       msg_dbg(buf_msg(buf), ">DEF-RETR>");
+                       l_ptr->retransm_queue_head = mod(++r_q_head);
+                       l_ptr->retransm_queue_size = --r_q_size;
+                       l_ptr->stats.retransmitted++;
+                       return TIPC_OK;
+               } else {
+                       l_ptr->stats.bearer_congs++;
+                       msg_dbg(buf_msg(buf), "|>DEF-RETR>");
+                       return PUSH_FAILED;
+               }
+       }
+
+       /* Send deferred protocol message, if any: */
+
+       buf = l_ptr->proto_msg_queue;
+       if (buf) {
+               msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
+               msg_set_bcast_ack(buf_msg(buf),l_ptr->owner->bclink.last_in); 
+               if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+                       msg_dbg(buf_msg(buf), ">DEF-PROT>");
+                       l_ptr->unacked_window = 0;
+                       buf_discard(buf);
+                       l_ptr->proto_msg_queue = 0;
+                       return TIPC_OK;
+               } else {
+                       msg_dbg(buf_msg(buf), "|>DEF-PROT>");
+                       l_ptr->stats.bearer_congs++;
+                       return PUSH_FAILED;
+               }
+       }
+
+       /* Send one deferred data message, if send window not full: */
+
+       buf = l_ptr->next_out;
+       if (buf) {
+               struct tipc_msg *msg = buf_msg(buf);
+               u32 next = msg_seqno(msg);
+               u32 first = msg_seqno(buf_msg(l_ptr->first_out));
+
+               if (mod(next - first) < l_ptr->queue_limit[0]) {
+                       msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
+                       msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
+                       if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+                               if (msg_user(msg) == MSG_BUNDLER)
+                                       msg_set_type(msg, CLOSED_MSG);
+                               msg_dbg(msg, ">PUSH-DATA>");
+                               l_ptr->next_out = buf->next;
+                               return TIPC_OK;
+                       } else {
+                               msg_dbg(msg, "|PUSH-DATA|");
+                               l_ptr->stats.bearer_congs++;
+                               return PUSH_FAILED;
+                       }
+               }
+       }
+       return PUSH_FINISHED;
+}
+
+/*
+ * push_queue(): push out the unsent messages of a link where
+ *               congestion has abated. Node is locked
+ */
+void link_push_queue(struct link *l_ptr)
+{
+       u32 res;
+
+       if (bearer_congested(l_ptr->b_ptr, l_ptr))
+               return;
+
+       do {
+               res = link_push_packet(l_ptr);
+       }
+       while (res == TIPC_OK);
+       if (res == PUSH_FAILED)
+               bearer_schedule(l_ptr->b_ptr, l_ptr);
+}
+
+void link_retransmit(struct link *l_ptr, struct sk_buff *buf, 
+                    u32 retransmits)
+{
+       struct tipc_msg *msg;
+
+       dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
+
+       if (bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) {
+               msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>");
+               dbg_print_link(l_ptr, "   ");
+               l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
+               l_ptr->retransm_queue_size = retransmits;
+               return;
+       }
+       while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
+               msg = buf_msg(buf);
+               msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
+               msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
+               if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+                        /* Catch if retransmissions fail repeatedly: */
+                        if (l_ptr->last_retransmitted == msg_seqno(msg)) {
+                                if (++l_ptr->stale_count > 100) {
+                                        msg_print(CONS, buf_msg(buf), ">RETR>");
+                                        info("...Retransmitted %u times\n",
+                                            l_ptr->stale_count);
+                                        link_print(l_ptr, CONS, "Resetting Link\n");;
+                                        link_reset(l_ptr);
+                                        break;
+                                }
+                        } else {
+                                l_ptr->stale_count = 0;
+                        }
+                        l_ptr->last_retransmitted = msg_seqno(msg);
+
+                       msg_dbg(buf_msg(buf), ">RETR>");
+                       buf = buf->next;
+                       retransmits--;
+                       l_ptr->stats.retransmitted++;
+               } else {
+                       bearer_schedule(l_ptr->b_ptr, l_ptr);
+                       l_ptr->stats.bearer_congs++;
+                       l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
+                       l_ptr->retransm_queue_size = retransmits;
+                       return;
+               }
+       }
+       l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
+}
+
+/* 
+ * link_recv_non_seq: Receive packets which are outside
+ *                    the link sequence flow
+ */
+
+static void link_recv_non_seq(struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+
+       if (msg_user(msg) ==  LINK_CONFIG)
+               disc_recv_msg(buf);
+       else
+               bclink_recv_pkt(buf);
+}
+
+/** 
+ * link_insert_deferred_queue - insert deferred messages back into receive chain
+ */
+
+static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr, 
+                                                 struct sk_buff *buf)
+{
+       u32 seq_no;
+
+       if (l_ptr->oldest_deferred_in == NULL)
+               return buf;
+
+       seq_no = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
+       if (seq_no == mod(l_ptr->next_in_no)) {
+               l_ptr->newest_deferred_in->next = buf;
+               buf = l_ptr->oldest_deferred_in;
+               l_ptr->oldest_deferred_in = NULL;
+               l_ptr->deferred_inqueue_sz = 0;
+       }
+       return buf;
+}
+
+void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
+{
+       read_lock_bh(&net_lock);
+       while (head) {
+               struct bearer *b_ptr;
+               struct node *n_ptr;
+               struct link *l_ptr;
+               struct sk_buff *crs;
+               struct sk_buff *buf = head;
+               struct tipc_msg *msg = buf_msg(buf);
+               u32 seq_no = msg_seqno(msg);
+               u32 ackd = msg_ack(msg);
+               u32 released = 0;
+               int type;
+
+               b_ptr = (struct bearer *)tb_ptr;
+               TIPC_SKB_CB(buf)->handle = b_ptr;
+
+               head = head->next;
+               if (unlikely(msg_version(msg) != TIPC_VERSION))
+                       goto cont;
+#if 0
+               if (msg_user(msg) != LINK_PROTOCOL)
+#endif
+                       msg_dbg(msg,"<REC<");
+
+               if (unlikely(msg_non_seq(msg))) {
+                       link_recv_non_seq(buf);
+                       continue;
+               }
+               n_ptr = node_find(msg_prevnode(msg));
+               if (unlikely(!n_ptr))
+                       goto cont;
+
+               node_lock(n_ptr);
+               l_ptr = n_ptr->links[b_ptr->identity];
+               if (unlikely(!l_ptr)) {
+                       node_unlock(n_ptr);
+                       goto cont;
+               }
+               /* 
+                * Release acked messages 
+                */
+               if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
+                       if (node_is_up(n_ptr) && n_ptr->bclink.supported)
+                               bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
+               }
+
+               crs = l_ptr->first_out;
+               while ((crs != l_ptr->next_out) && 
+                      less_eq(msg_seqno(buf_msg(crs)), ackd)) {
+                       struct sk_buff *next = crs->next;
+
+                       buf_discard(crs);
+                       crs = next;
+                       released++;
+               }
+               if (released) {
+                       l_ptr->first_out = crs;
+                       l_ptr->out_queue_size -= released;
+               }
+               if (unlikely(l_ptr->next_out))
+                       link_push_queue(l_ptr);
+               if (unlikely(!list_empty(&l_ptr->waiting_ports)))
+                       link_wakeup_ports(l_ptr, 0);
+               if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
+                       l_ptr->stats.sent_acks++;
+                       link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+               }
+
+protocol_check:
+               if (likely(link_working_working(l_ptr))) {
+                       if (likely(seq_no == mod(l_ptr->next_in_no))) {
+                               l_ptr->next_in_no++;
+                               if (unlikely(l_ptr->oldest_deferred_in))
+                                       head = link_insert_deferred_queue(l_ptr,
+                                                                         head);
+                               if (likely(msg_is_dest(msg, tipc_own_addr))) {
+deliver:
+                                       if (likely(msg_isdata(msg))) {
+                                               node_unlock(n_ptr);
+                                               port_recv_msg(buf);
+                                               continue;
+                                       }
+                                       switch (msg_user(msg)) {
+                                       case MSG_BUNDLER:
+                                               l_ptr->stats.recv_bundles++;
+                                               l_ptr->stats.recv_bundled += 
+                                                       msg_msgcnt(msg);
+                                               node_unlock(n_ptr);
+                                               link_recv_bundle(buf);
+                                               continue;
+                                       case ROUTE_DISTRIBUTOR:
+                                               node_unlock(n_ptr);
+                                               cluster_recv_routing_table(buf);
+                                               continue;
+                                       case NAME_DISTRIBUTOR:
+                                               node_unlock(n_ptr);
+                                               named_recv(buf);
+                                               continue;
+                                       case CONN_MANAGER:
+                                               node_unlock(n_ptr);
+                                               port_recv_proto_msg(buf);
+                                               continue;
+                                       case MSG_FRAGMENTER:
+                                               l_ptr->stats.recv_fragments++;
+                                               if (link_recv_fragment(
+                                                       &l_ptr->defragm_buf, 
+                                                       &buf, &msg)) {
+                                                       l_ptr->stats.recv_fragmented++;
+                                                       goto deliver;
+                                               }
+                                               break;
+                                       case CHANGEOVER_PROTOCOL:
+                                               type = msg_type(msg);
+                                               if (link_recv_changeover_msg(
+                                                       &l_ptr, &buf)) {
+                                                       msg = buf_msg(buf);
+                                                       seq_no = msg_seqno(msg);
+                                                       TIPC_SKB_CB(buf)->handle 
+                                                               = b_ptr;
+                                                       if (type == ORIGINAL_MSG)
+                                                               goto deliver;
+                                                       goto protocol_check;
+                                               }
+                                               break;
+                                       }
+                               }
+                               node_unlock(n_ptr);
+                               net_route_msg(buf);
+                               continue;
+                       }
+                       link_handle_out_of_seq_msg(l_ptr, buf);
+                       head = link_insert_deferred_queue(l_ptr, head);
+                       node_unlock(n_ptr);
+                       continue;
+               }
+
+               if (msg_user(msg) == LINK_PROTOCOL) {
+                       link_recv_proto_msg(l_ptr, buf);
+                       head = link_insert_deferred_queue(l_ptr, head);
+                       node_unlock(n_ptr);
+                       continue;
+               }
+               msg_dbg(msg,"NSEQ<REC<");
+               link_state_event(l_ptr, TRAFFIC_MSG_EVT);
+
+               if (link_working_working(l_ptr)) {
+                       /* Re-insert in front of queue */
+                       msg_dbg(msg,"RECV-REINS:");
+                       buf->next = head;
+                       head = buf;
+                       node_unlock(n_ptr);
+                       continue;
+               }
+               node_unlock(n_ptr);
+cont:
+               buf_discard(buf);
+       }
+       read_unlock_bh(&net_lock);
+}
+
+/* 
+ * link_defer_buf(): Sort a received out-of-sequence packet 
+ *                   into the deferred reception queue.
+ * Returns the increase of the queue length,i.e. 0 or 1
+ */
+
+u32 link_defer_pkt(struct sk_buff **head,
+                  struct sk_buff **tail,
+                  struct sk_buff *buf)
+{
+       struct sk_buff *prev = 0;
+       struct sk_buff *crs = *head;
+       u32 seq_no = msg_seqno(buf_msg(buf));
+
+       buf->next = NULL;
+
+       /* Empty queue ? */
+       if (*head == NULL) {
+               *head = *tail = buf;
+               return 1;
+       }
+
+       /* Last ? */
+       if (less(msg_seqno(buf_msg(*tail)), seq_no)) {
+               (*tail)->next = buf;
+               *tail = buf;
+               return 1;
+       }
+
+       /* Scan through queue and sort it in */
+       do {
+               struct tipc_msg *msg = buf_msg(crs);
+
+               if (less(seq_no, msg_seqno(msg))) {
+                       buf->next = crs;
+                       if (prev)
+                               prev->next = buf;
+                       else
+                               *head = buf;   
+                       return 1;
+               }
+               if (seq_no == msg_seqno(msg)) {
+                       break;
+               }
+               prev = crs;
+               crs = crs->next;
+       }
+       while (crs);
+
+       /* Message is a duplicate of an existing message */
+
+       buf_discard(buf);
+       return 0;
+}
+
+/** 
+ * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
+ */
+
+static void link_handle_out_of_seq_msg(struct link *l_ptr, 
+                                      struct sk_buff *buf)
+{
+       u32 seq_no = msg_seqno(buf_msg(buf));
+
+       if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
+               link_recv_proto_msg(l_ptr, buf);
+               return;
+       }
+
+       dbg("rx OOS msg: seq_no %u, expecting %u (%u)\n", 
+           seq_no, mod(l_ptr->next_in_no), l_ptr->next_in_no);
+
+       /* Record OOS packet arrival (force mismatch on next timeout) */
+
+       l_ptr->checkpoint--;
+
+       /* 
+        * Discard packet if a duplicate; otherwise add it to deferred queue
+        * and notify peer of gap as per protocol specification
+        */
+
+       if (less(seq_no, mod(l_ptr->next_in_no))) {
+               l_ptr->stats.duplicates++;
+               buf_discard(buf);
+               return;
+       }
+
+       if (link_defer_pkt(&l_ptr->oldest_deferred_in,
+                          &l_ptr->newest_deferred_in, buf)) {
+               l_ptr->deferred_inqueue_sz++;
+               l_ptr->stats.deferred_recv++;
+               if ((l_ptr->deferred_inqueue_sz % 16) == 1)
+                       link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+       } else
+               l_ptr->stats.duplicates++;
+}
+
+/*
+ * Send protocol message to the other endpoint.
+ */
+void link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
+                        u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
+{
+       struct sk_buff *buf = 0;
+       struct tipc_msg *msg = l_ptr->pmsg;
+        u32 msg_size = sizeof(l_ptr->proto_msg);
+
+       if (link_blocked(l_ptr))
+               return;
+       msg_set_type(msg, msg_typ);
+       msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
+       msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in)); 
+       msg_set_last_bcast(msg, bclink_get_last_sent());
+
+       if (msg_typ == STATE_MSG) {
+               u32 next_sent = mod(l_ptr->next_out_no);
+
+               if (!link_is_up(l_ptr))
+                       return;
+               if (l_ptr->next_out)
+                       next_sent = msg_seqno(buf_msg(l_ptr->next_out));
+               msg_set_next_sent(msg, next_sent);
+               if (l_ptr->oldest_deferred_in) {
+                       u32 rec = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
+                       gap = mod(rec - mod(l_ptr->next_in_no));
+               }
+               msg_set_seq_gap(msg, gap);
+               if (gap)
+                       l_ptr->stats.sent_nacks++;
+               msg_set_link_tolerance(msg, tolerance);
+               msg_set_linkprio(msg, priority);
+               msg_set_max_pkt(msg, ack_mtu);
+               msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
+               msg_set_probe(msg, probe_msg != 0);
+               if (probe_msg) { 
+                       u32 mtu = l_ptr->max_pkt;
+
+                        if ((mtu < l_ptr->max_pkt_target) &&
+                           link_working_working(l_ptr) &&
+                           l_ptr->fsm_msg_cnt) {
+                               msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
+                                if (l_ptr->max_pkt_probes == 10) {
+                                        l_ptr->max_pkt_target = (msg_size - 4);
+                                        l_ptr->max_pkt_probes = 0;
+                                       msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
+                                }
+                               l_ptr->max_pkt_probes++;
+                        }
+
+                       l_ptr->stats.sent_probes++;
+                }
+               l_ptr->stats.sent_states++;
+       } else {                /* RESET_MSG or ACTIVATE_MSG */
+               msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1));
+               msg_set_seq_gap(msg, 0);
+               msg_set_next_sent(msg, 1);
+               msg_set_link_tolerance(msg, l_ptr->tolerance);
+               msg_set_linkprio(msg, l_ptr->priority);
+               msg_set_max_pkt(msg, l_ptr->max_pkt_target);
+       }
+
+       if (node_has_redundant_links(l_ptr->owner)) {
+               msg_set_redundant_link(msg);
+       } else {
+               msg_clear_redundant_link(msg);
+       }
+       msg_set_linkprio(msg, l_ptr->priority);
+
+       /* Ensure sequence number will not fit : */
+
+       msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2)));
+
+       /* Congestion? */
+
+       if (bearer_congested(l_ptr->b_ptr, l_ptr)) {
+               if (!l_ptr->proto_msg_queue) {
+                       l_ptr->proto_msg_queue =
+                               buf_acquire(sizeof(l_ptr->proto_msg));
+               }
+               buf = l_ptr->proto_msg_queue;
+               if (!buf)
+                       return;
+               memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
+               return;
+       }
+       msg_set_timestamp(msg, jiffies_to_msecs(jiffies));
+
+       /* Message can be sent */
+
+       msg_dbg(msg, ">>");
+
+       buf = buf_acquire(msg_size);
+       if (!buf)
+               return;
+
+       memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
+        msg_set_size(buf_msg(buf), msg_size);
+
+       if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
+               l_ptr->unacked_window = 0;
+               buf_discard(buf);
+               return;
+       }
+
+       /* New congestion */
+       bearer_schedule(l_ptr->b_ptr, l_ptr);
+       l_ptr->proto_msg_queue = buf;
+       l_ptr->stats.bearer_congs++;
+}
+
+/*
+ * Receive protocol message :
+ * Note that network plane id propagates through the network, and may 
+ * change at any time. The node with lowest address rules    
+ */
+
+static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
+{
+       u32 rec_gap = 0;
+       u32 max_pkt_info;
+        u32 max_pkt_ack;
+       u32 msg_tol;
+       struct tipc_msg *msg = buf_msg(buf);
+
+       dbg("AT(%u):", jiffies_to_msecs(jiffies));
+       msg_dbg(msg, "<<");
+       if (link_blocked(l_ptr))
+               goto exit;
+
+       /* record unnumbered packet arrival (force mismatch on next timeout) */
+
+       l_ptr->checkpoint--;
+
+       if (l_ptr->b_ptr->net_plane != msg_net_plane(msg))
+               if (tipc_own_addr > msg_prevnode(msg))
+                       l_ptr->b_ptr->net_plane = msg_net_plane(msg);
+
+       l_ptr->owner->permit_changeover = msg_redundant_link(msg);
+
+       switch (msg_type(msg)) {
+       
+       case RESET_MSG:
+               if (!link_working_unknown(l_ptr) && l_ptr->peer_session) {
+                       if (msg_session(msg) == l_ptr->peer_session) {
+                               dbg("Duplicate RESET: %u<->%u\n",
+                                   msg_session(msg), l_ptr->peer_session);                                     
+                               break; /* duplicate: ignore */
+                       }
+               }
+               /* fall thru' */
+       case ACTIVATE_MSG:
+               /* Update link settings according other endpoint's values */
+
+               strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg));
+
+               if ((msg_tol = msg_link_tolerance(msg)) &&
+                   (msg_tol > l_ptr->tolerance))
+                       link_set_supervision_props(l_ptr, msg_tol);
+
+               if (msg_linkprio(msg) > l_ptr->priority)
+                       l_ptr->priority = msg_linkprio(msg);
+
+               max_pkt_info = msg_max_pkt(msg);
+                if (max_pkt_info) {
+                       if (max_pkt_info < l_ptr->max_pkt_target)
+                               l_ptr->max_pkt_target = max_pkt_info;
+                       if (l_ptr->max_pkt > l_ptr->max_pkt_target)
+                               l_ptr->max_pkt = l_ptr->max_pkt_target;
+               } else {
+                        l_ptr->max_pkt = l_ptr->max_pkt_target;
+               }
+               l_ptr->owner->bclink.supported = (max_pkt_info != 0);
+
+               link_state_event(l_ptr, msg_type(msg));
+
+               l_ptr->peer_session = msg_session(msg);
+               l_ptr->peer_bearer_id = msg_bearer_id(msg);
+
+               /* Synchronize broadcast sequence numbers */
+               if (!node_has_redundant_links(l_ptr->owner)) {
+                       l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg));
+               }
+               break;
+       case STATE_MSG:
+
+               if ((msg_tol = msg_link_tolerance(msg)))
+                       link_set_supervision_props(l_ptr, msg_tol);
+               
+               if (msg_linkprio(msg) && 
+                   (msg_linkprio(msg) != l_ptr->priority)) {
+                       warn("Changing prio <%s>: %u->%u\n",
+                            l_ptr->name, l_ptr->priority, msg_linkprio(msg));
+                       l_ptr->priority = msg_linkprio(msg);
+                       link_reset(l_ptr); /* Enforce change to take effect */
+                       break;
+               }
+               link_state_event(l_ptr, TRAFFIC_MSG_EVT);
+               l_ptr->stats.recv_states++;
+               if (link_reset_unknown(l_ptr))
+                       break;
+
+               if (less_eq(mod(l_ptr->next_in_no), msg_next_sent(msg))) {
+                       rec_gap = mod(msg_next_sent(msg) - 
+                                     mod(l_ptr->next_in_no));
+               }
+
+               max_pkt_ack = msg_max_pkt(msg);
+                if (max_pkt_ack > l_ptr->max_pkt) {
+                        dbg("Link <%s> updated MTU %u -> %u\n",
+                            l_ptr->name, l_ptr->max_pkt, max_pkt_ack);
+                        l_ptr->max_pkt = max_pkt_ack;
+                        l_ptr->max_pkt_probes = 0;
+                }
+
+               max_pkt_ack = 0;
+                if (msg_probe(msg)) {
+                       l_ptr->stats.recv_probes++;
+                        if (msg_size(msg) > sizeof(l_ptr->proto_msg)) {
+                                max_pkt_ack = msg_size(msg);
+                        }
+                }
+
+               /* Protocol message before retransmits, reduce loss risk */
+
+               bclink_check_gap(l_ptr->owner, msg_last_bcast(msg));
+
+               if (rec_gap || (msg_probe(msg))) {
+                       link_send_proto_msg(l_ptr, STATE_MSG,
+                                           0, rec_gap, 0, 0, max_pkt_ack);
+               }
+               if (msg_seq_gap(msg)) {
+                       msg_dbg(msg, "With Gap:");
+                       l_ptr->stats.recv_nacks++;
+                       link_retransmit(l_ptr, l_ptr->first_out,
+                                       msg_seq_gap(msg));
+               }
+               break;
+       default:
+               msg_dbg(buf_msg(buf), "<DISCARDING UNKNOWN<");
+       }
+exit:
+       buf_discard(buf);
+}
+
+
+/*
+ * link_tunnel(): Send one message via a link belonging to 
+ * another bearer. Owner node is locked.
+ */
+void link_tunnel(struct link *l_ptr, 
+           struct tipc_msg *tunnel_hdr, 
+           struct tipc_msg  *msg,
+           u32 selector)
+{
+       struct link *tunnel;
+       struct sk_buff *buf;
+       u32 length = msg_size(msg);
+
+       tunnel = l_ptr->owner->active_links[selector & 1];
+       if (!link_is_up(tunnel))
+               return;
+       msg_set_size(tunnel_hdr, length + INT_H_SIZE);
+       buf = buf_acquire(length + INT_H_SIZE);
+       if (!buf)
+               return;
+       memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
+       memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
+       dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
+       msg_dbg(buf_msg(buf), ">SEND>");
+       assert(tunnel);
+       link_send_buf(tunnel, buf);
+}
+
+
+
+/*
+ * changeover(): Send whole message queue via the remaining link
+ *               Owner node is locked.
+ */
+
+void link_changeover(struct link *l_ptr)
+{
+       u32 msgcount = l_ptr->out_queue_size;
+       struct sk_buff *crs = l_ptr->first_out;
+       struct link *tunnel = l_ptr->owner->active_links[0];
+       int split_bundles = node_has_redundant_links(l_ptr->owner);
+       struct tipc_msg tunnel_hdr;
+
+       if (!tunnel)
+               return;
+
+       if (!l_ptr->owner->permit_changeover)
+               return;
+
+       msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
+                ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+       msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
+       msg_set_msgcnt(&tunnel_hdr, msgcount);
+       if (!l_ptr->first_out) {
+               struct sk_buff *buf;
+
+               assert(!msgcount);
+               buf = buf_acquire(INT_H_SIZE);
+               if (buf) {
+                       memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
+                       msg_set_size(&tunnel_hdr, INT_H_SIZE);
+                       dbg("%c->%c:", l_ptr->b_ptr->net_plane,
+                           tunnel->b_ptr->net_plane);
+                       msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
+                       link_send_buf(tunnel, buf);
+               } else {
+                       warn("Memory squeeze; link changeover failed\n");
+               }
+               return;
+       }
+       while (crs) {
+               struct tipc_msg *msg = buf_msg(crs);
+
+               if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) {
+                       u32 msgcount = msg_msgcnt(msg);
+                       struct tipc_msg *m = msg_get_wrapped(msg);
+                       unchar* pos = (unchar*)m;
+
+                       while (msgcount--) {
+                               msg_set_seqno(m,msg_seqno(msg));
+                               link_tunnel(l_ptr, &tunnel_hdr, m,
+                                           msg_link_selector(m));
+                               pos += align(msg_size(m));
+                               m = (struct tipc_msg *)pos;
+                       }
+               } else {
+                       link_tunnel(l_ptr, &tunnel_hdr, msg,
+                                   msg_link_selector(msg));
+               }
+               crs = crs->next;
+       }
+}
+
+void link_send_duplicate(struct link *l_ptr, struct link *tunnel)
+{
+       struct sk_buff *iter;
+       struct tipc_msg tunnel_hdr;
+
+       msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
+                DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
+       msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
+       msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
+       iter = l_ptr->first_out;
+       while (iter) {
+               struct sk_buff *outbuf;
+               struct tipc_msg *msg = buf_msg(iter);
+               u32 length = msg_size(msg);
+
+               if (msg_user(msg) == MSG_BUNDLER)
+                       msg_set_type(msg, CLOSED_MSG);
+               msg_set_ack(msg, mod(l_ptr->next_in_no - 1));   /* Update */
+               msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); 
+               msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
+               outbuf = buf_acquire(length + INT_H_SIZE);
+               if (outbuf == NULL) {
+                       warn("Memory squeeze; buffer duplication failed\n");
+                       return;
+               }
+               memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
+               memcpy(outbuf->data + INT_H_SIZE, iter->data, length);
+               dbg("%c->%c:", l_ptr->b_ptr->net_plane,
+                   tunnel->b_ptr->net_plane);
+               msg_dbg(buf_msg(outbuf), ">SEND>");
+               link_send_buf(tunnel, outbuf);
+               if (!link_is_up(l_ptr))
+                       return;
+               iter = iter->next;
+       }
+}
+
+
+
+/**
+ * buf_extract - extracts embedded TIPC message from another message
+ * @skb: encapsulating message buffer
+ * @from_pos: offset to extract from
+ *
+ * Returns a new message buffer containing an embedded message.  The 
+ * encapsulating message itself is left unchanged.
+ */
+
+static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
+{
+       struct tipc_msg *msg = (struct tipc_msg *)(skb->data + from_pos);
+       u32 size = msg_size(msg);
+       struct sk_buff *eb;
+
+       eb = buf_acquire(size);
+       if (eb)
+               memcpy(eb->data, (unchar *)msg, size);
+       return eb;
+}
+
+/* 
+ *  link_recv_changeover_msg(): Receive tunneled packet sent
+ *  via other link. Node is locked. Return extracted buffer.
+ */
+
+static int link_recv_changeover_msg(struct link **l_ptr,
+                                   struct sk_buff **buf)
+{
+       struct sk_buff *tunnel_buf = *buf;
+       struct link *dest_link;
+       struct tipc_msg *msg;
+       struct tipc_msg *tunnel_msg = buf_msg(tunnel_buf);
+       u32 msg_typ = msg_type(tunnel_msg);
+       u32 msg_count = msg_msgcnt(tunnel_msg);
+
+       dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
+       assert(dest_link != *l_ptr);
+       if (!dest_link) {
+               msg_dbg(tunnel_msg, "NOLINK/<REC<");
+               goto exit;
+       }
+       dbg("%c<-%c:", dest_link->b_ptr->net_plane,
+           (*l_ptr)->b_ptr->net_plane);
+       *l_ptr = dest_link;
+       msg = msg_get_wrapped(tunnel_msg);
+
+       if (msg_typ == DUPLICATE_MSG) {
+               if (less(msg_seqno(msg), mod(dest_link->next_in_no))) {
+                       msg_dbg(tunnel_msg, "DROP/<REC<");
+                       goto exit;
+               }
+               *buf = buf_extract(tunnel_buf,INT_H_SIZE);
+               if (*buf == NULL) {
+                       warn("Memory squeeze; failed to extract msg\n");
+                       goto exit;
+               }
+               msg_dbg(tunnel_msg, "TNL<REC<");
+               buf_discard(tunnel_buf);
+               return 1;
+       }
+
+       /* First original message ?: */
+
+       if (link_is_up(dest_link)) {
+               msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
+               link_reset(dest_link);
+               dest_link->exp_msg_count = msg_count;
+               if (!msg_count)
+                       goto exit;
+       } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
+               msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
+               dest_link->exp_msg_count = msg_count;
+               if (!msg_count)
+                       goto exit;
+       }
+
+       /* Receive original message */
+
+       if (dest_link->exp_msg_count == 0) {
+               msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
+               dbg_print_link(dest_link, "LINK:");
+               goto exit;
+       }
+       dest_link->exp_msg_count--;
+       if (less(msg_seqno(msg), dest_link->reset_checkpoint)) {
+               msg_dbg(tunnel_msg, "DROP/DUPL/<REC<");
+               goto exit;
+       } else {
+               *buf = buf_extract(tunnel_buf, INT_H_SIZE);
+               if (*buf != NULL) {
+                       msg_dbg(tunnel_msg, "TNL<REC<");
+                       buf_discard(tunnel_buf);
+                       return 1;
+               } else {
+                       warn("Memory squeeze; dropped incoming msg\n");
+               }
+       }
+exit:
+       *buf = 0;
+       buf_discard(tunnel_buf);
+       return 0;
+}
+
+/*
+ *  Bundler functionality:
+ */
+void link_recv_bundle(struct sk_buff *buf)
+{
+       u32 msgcount = msg_msgcnt(buf_msg(buf));
+       u32 pos = INT_H_SIZE;
+       struct sk_buff *obuf;
+
+       msg_dbg(buf_msg(buf), "<BNDL<: ");
+       while (msgcount--) {
+               obuf = buf_extract(buf, pos);
+               if (obuf == NULL) {
+                       char addr_string[16];
+
+                       warn("Buffer allocation failure;\n");
+                       warn("  incoming message(s) from %s lost\n",
+                            addr_string_fill(addr_string, 
+                                             msg_orignode(buf_msg(buf))));
+                       return;
+               };
+               pos += align(msg_size(buf_msg(obuf)));
+               msg_dbg(buf_msg(obuf), "     /");
+               net_route_msg(obuf);
+       }
+       buf_discard(buf);
+}
+
+/*
+ *  Fragmentation/defragmentation:
+ */
+
+
+/* 
+ * link_send_long_buf: Entry for buffers needing fragmentation.
+ * The buffer is complete, inclusive total message length. 
+ * Returns user data length.
+ */
+int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
+{
+       struct tipc_msg *inmsg = buf_msg(buf);
+       struct tipc_msg fragm_hdr;
+       u32 insize = msg_size(inmsg);
+       u32 dsz = msg_data_sz(inmsg);
+       unchar *crs = buf->data;
+       u32 rest = insize;
+       u32 pack_sz = link_max_pkt(l_ptr);
+       u32 fragm_sz = pack_sz - INT_H_SIZE;
+       u32 fragm_no = 1;
+       u32 destaddr = msg_destnode(inmsg);
+
+       if (msg_short(inmsg))
+               destaddr = l_ptr->addr;
+
+       if (msg_routed(inmsg))
+               msg_set_prevnode(inmsg, tipc_own_addr);
+
+       /* Prepare reusable fragment header: */
+
+       msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
+                TIPC_OK, INT_H_SIZE, destaddr);
+       msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
+       msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
+       msg_set_fragm_no(&fragm_hdr, fragm_no);
+       l_ptr->stats.sent_fragmented++;
+
+       /* Chop up message: */
+
+       while (rest > 0) {
+               struct sk_buff *fragm;
+
+               if (rest <= fragm_sz) {
+                       fragm_sz = rest;
+                       msg_set_type(&fragm_hdr, LAST_FRAGMENT);
+               }
+               fragm = buf_acquire(fragm_sz + INT_H_SIZE);
+               if (fragm == NULL) {
+                       warn("Memory squeeze; failed to fragment msg\n");
+                       dsz = -ENOMEM;
+                       goto exit;
+               }
+               msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
+               memcpy(fragm->data, (unchar *)&fragm_hdr, INT_H_SIZE);
+               memcpy(fragm->data + INT_H_SIZE, crs, fragm_sz);
+
+               /*  Send queued messages first, if any: */
+
+               l_ptr->stats.sent_fragments++;
+               link_send_buf(l_ptr, fragm);
+               if (!link_is_up(l_ptr))
+                       return dsz;
+               msg_set_fragm_no(&fragm_hdr, ++fragm_no);
+               rest -= fragm_sz;
+               crs += fragm_sz;
+               msg_set_type(&fragm_hdr, FRAGMENT);
+       }
+exit:
+       buf_discard(buf);
+       return dsz;
+}
+
+/* 
+ * A pending message being re-assembled must store certain values 
+ * to handle subsequent fragments correctly. The following functions 
+ * help storing these values in unused, available fields in the
+ * pending message. This makes dynamic memory allocation unecessary.
+ */
+
+static inline u32 get_long_msg_seqno(struct sk_buff *buf)
+{
+       return msg_seqno(buf_msg(buf));
+}
+
+static inline void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
+{
+       msg_set_seqno(buf_msg(buf), seqno);
+}
+
+static inline u32 get_fragm_size(struct sk_buff *buf)
+{
+       return msg_ack(buf_msg(buf));
+}
+
+static inline void set_fragm_size(struct sk_buff *buf, u32 sz)
+{
+       msg_set_ack(buf_msg(buf), sz);
+}
+
+static inline u32 get_expected_frags(struct sk_buff *buf)
+{
+       return msg_bcast_ack(buf_msg(buf));
+}
+
+static inline void set_expected_frags(struct sk_buff *buf, u32 exp)
+{
+       msg_set_bcast_ack(buf_msg(buf), exp);
+}
+
+static inline u32 get_timer_cnt(struct sk_buff *buf)
+{
+       return msg_reroute_cnt(buf_msg(buf));
+}
+
+static inline void incr_timer_cnt(struct sk_buff *buf)
+{
+       msg_incr_reroute_cnt(buf_msg(buf));
+}
+
+/* 
+ * link_recv_fragment(): Called with node lock on. Returns 
+ * the reassembled buffer if message is complete.
+ */
+int link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb, 
+                      struct tipc_msg **m)
+{
+       struct sk_buff *prev = 0;
+       struct sk_buff *fbuf = *fb;
+       struct tipc_msg *fragm = buf_msg(fbuf);
+       struct sk_buff *pbuf = *pending;
+       u32 long_msg_seq_no = msg_long_msgno(fragm);
+
+       *fb = 0;
+       msg_dbg(fragm,"FRG<REC<");
+
+       /* Is there an incomplete message waiting for this fragment? */
+
+       while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no)
+                       || (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
+               prev = pbuf;
+               pbuf = pbuf->next;
+       }
+
+       if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
+               struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
+               u32 msg_sz = msg_size(imsg);
+               u32 fragm_sz = msg_data_sz(fragm);
+               u32 exp_fragm_cnt = msg_sz/fragm_sz + !!(msg_sz % fragm_sz);
+               u32 max =  TIPC_MAX_USER_MSG_SIZE + LONG_H_SIZE;
+               if (msg_type(imsg) == TIPC_MCAST_MSG)
+                       max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
+               if (msg_size(imsg) > max) {
+                       msg_dbg(fragm,"<REC<Oversized: ");
+                       buf_discard(fbuf);
+                       return 0;
+               }
+               pbuf = buf_acquire(msg_size(imsg));
+               if (pbuf != NULL) {
+                       pbuf->next = *pending;
+                       *pending = pbuf;
+                       memcpy(pbuf->data, (unchar *)imsg, msg_data_sz(fragm));
+
+                       /*  Prepare buffer for subsequent fragments. */
+
+                       set_long_msg_seqno(pbuf, long_msg_seq_no); 
+                       set_fragm_size(pbuf,fragm_sz); 
+                       set_expected_frags(pbuf,exp_fragm_cnt - 1); 
+               } else {
+                       warn("Memory squeeze; got no defragmenting buffer\n");
+               }
+               buf_discard(fbuf);
+               return 0;
+       } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
+               u32 dsz = msg_data_sz(fragm);
+               u32 fsz = get_fragm_size(pbuf);
+               u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
+               u32 exp_frags = get_expected_frags(pbuf) - 1;
+               memcpy(pbuf->data + crs, msg_data(fragm), dsz);
+               buf_discard(fbuf);
+
+               /* Is message complete? */
+
+               if (exp_frags == 0) {
+                       if (prev)
+                               prev->next = pbuf->next;
+                       else
+                               *pending = pbuf->next;
+                       msg_reset_reroute_cnt(buf_msg(pbuf));
+                       *fb = pbuf;
+                       *m = buf_msg(pbuf);
+                       return 1;
+               }
+               set_expected_frags(pbuf,exp_frags);     
+               return 0;
+       }
+       dbg(" Discarding orphan fragment %x\n",fbuf);
+       msg_dbg(fragm,"ORPHAN:");
+       dbg("Pending long buffers:\n");
+       dbg_print_buf_chain(*pending);
+       buf_discard(fbuf);
+       return 0;
+}
+
+/**
+ * link_check_defragm_bufs - flush stale incoming message fragments
+ * @l_ptr: pointer to link
+ */
+
+static void link_check_defragm_bufs(struct link *l_ptr)
+{
+       struct sk_buff *prev = 0;
+       struct sk_buff *next = 0;
+       struct sk_buff *buf = l_ptr->defragm_buf;
+
+       if (!buf)
+               return;
+       if (!link_working_working(l_ptr))
+               return;
+       while (buf) {
+               u32 cnt = get_timer_cnt(buf);
+
+               next = buf->next;
+               if (cnt < 4) {
+                       incr_timer_cnt(buf);
+                       prev = buf;
+               } else {
+                       dbg(" Discarding incomplete long buffer\n");
+                       msg_dbg(buf_msg(buf), "LONG:");
+                       dbg_print_link(l_ptr, "curr:");
+                       dbg("Pending long buffers:\n");
+                       dbg_print_buf_chain(l_ptr->defragm_buf);
+                       if (prev)
+                               prev->next = buf->next;
+                       else
+                               l_ptr->defragm_buf = buf->next;
+                       buf_discard(buf);
+               }
+               buf = next;
+       }
+}
+
+
+
+static void link_set_supervision_props(struct link *l_ptr, u32 tolerance)
+{
+       l_ptr->tolerance = tolerance;
+       l_ptr->continuity_interval =
+               ((tolerance / 4) > 500) ? 500 : tolerance / 4;
+       l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4);
+}
+
+
+void link_set_queue_limits(struct link *l_ptr, u32 window)
+{
+       /* Data messages from this node, inclusive FIRST_FRAGM */
+       l_ptr->queue_limit[DATA_LOW] = window;
+       l_ptr->queue_limit[DATA_MEDIUM] = (window / 3) * 4;
+       l_ptr->queue_limit[DATA_HIGH] = (window / 3) * 5;
+       l_ptr->queue_limit[DATA_CRITICAL] = (window / 3) * 6;
+       /* Transiting data messages,inclusive FIRST_FRAGM */
+       l_ptr->queue_limit[DATA_LOW + 4] = 300;
+       l_ptr->queue_limit[DATA_MEDIUM + 4] = 600;
+       l_ptr->queue_limit[DATA_HIGH + 4] = 900;
+       l_ptr->queue_limit[DATA_CRITICAL + 4] = 1200;
+       l_ptr->queue_limit[CONN_MANAGER] = 1200;
+       l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
+       l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
+       l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000;
+       /* FRAGMENT and LAST_FRAGMENT packets */
+       l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
+}
+
+/**
+ * link_find_link - locate link by name
+ * @name - ptr to link name string
+ * @node - ptr to area to be filled with ptr to associated node
+ * 
+ * Caller must hold 'net_lock' to ensure node and bearer are not deleted;
+ * this also prevents link deletion.
+ * 
+ * Returns pointer to link (or 0 if invalid link name).
+ */
+
+static struct link *link_find_link(const char *name, struct node **node)
+{
+       struct link_name link_name_parts;
+       struct bearer *b_ptr;
+       struct link *l_ptr; 
+
+       if (!link_name_validate(name, &link_name_parts))
+               return 0;
+
+       b_ptr = bearer_find_interface(link_name_parts.if_local);
+       if (!b_ptr)
+               return 0;
+
+       *node = node_find(link_name_parts.addr_peer); 
+       if (!*node)
+               return 0;
+
+       l_ptr = (*node)->links[b_ptr->identity];
+       if (!l_ptr || strcmp(l_ptr->name, name))
+               return 0;
+
+       return l_ptr;
+}
+
+struct sk_buff *link_cmd_config(const void *req_tlv_area, int req_tlv_space, 
+                               u16 cmd)
+{
+       struct tipc_link_config *args;
+        u32 new_value;
+       struct link *l_ptr;
+       struct node *node;
+        int res;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
+       new_value = ntohl(args->value);
+
+       if (!strcmp(args->name, bc_link_name)) {
+               if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
+                   (bclink_set_queue_limits(new_value) == 0))
+                       return cfg_reply_none();
+               return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+                                             " (cannot change setting on broadcast link)");
+       }
+
+       read_lock_bh(&net_lock);
+       l_ptr = link_find_link(args->name, &node); 
+       if (!l_ptr) {
+               read_unlock_bh(&net_lock);
+               return cfg_reply_error_string("link not found");
+       }
+
+       node_lock(node);
+       res = -EINVAL;
+       switch (cmd) {
+       case TIPC_CMD_SET_LINK_TOL: 
+               if ((new_value >= TIPC_MIN_LINK_TOL) && 
+                   (new_value <= TIPC_MAX_LINK_TOL)) {
+                       link_set_supervision_props(l_ptr, new_value);
+                       link_send_proto_msg(l_ptr, STATE_MSG, 
+                                           0, 0, new_value, 0, 0);
+                       res = TIPC_OK;
+               }
+               break;
+       case TIPC_CMD_SET_LINK_PRI: 
+               if (new_value < TIPC_NUM_LINK_PRI) {
+                       l_ptr->priority = new_value;
+                       link_send_proto_msg(l_ptr, STATE_MSG, 
+                                           0, 0, 0, new_value, 0);
+                       res = TIPC_OK;
+               }
+               break;
+       case TIPC_CMD_SET_LINK_WINDOW: 
+               if ((new_value >= TIPC_MIN_LINK_WIN) && 
+                   (new_value <= TIPC_MAX_LINK_WIN)) {
+                       link_set_queue_limits(l_ptr, new_value);
+                       res = TIPC_OK;
+               }
+               break;
+       }
+       node_unlock(node);
+
+       read_unlock_bh(&net_lock);
+       if (res)
+               return cfg_reply_error_string("cannot change link setting");
+
+       return cfg_reply_none();
+}
+
+/**
+ * link_reset_statistics - reset link statistics
+ * @l_ptr: pointer to link
+ */
+
+static void link_reset_statistics(struct link *l_ptr)
+{
+       memset(&l_ptr->stats, 0, sizeof(l_ptr->stats));
+       l_ptr->stats.sent_info = l_ptr->next_out_no;
+       l_ptr->stats.recv_info = l_ptr->next_in_no;
+}
+
+struct sk_buff *link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space)
+{
+       char *link_name;
+       struct link *l_ptr; 
+       struct node *node;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       link_name = (char *)TLV_DATA(req_tlv_area);
+       if (!strcmp(link_name, bc_link_name)) {
+               if (bclink_reset_stats())
+                       return cfg_reply_error_string("link not found");
+               return cfg_reply_none();
+       }
+
+       read_lock_bh(&net_lock);
+       l_ptr = link_find_link(link_name, &node); 
+       if (!l_ptr) {
+               read_unlock_bh(&net_lock);
+               return cfg_reply_error_string("link not found");
+       }
+
+       node_lock(node);
+       link_reset_statistics(l_ptr);
+       node_unlock(node);
+       read_unlock_bh(&net_lock);
+       return cfg_reply_none();
+}
+
+/**
+ * percent - convert count to a percentage of total (rounding up or down)
+ */
+
+static u32 percent(u32 count, u32 total)
+{
+       return (count * 100 + (total / 2)) / total;
+}
+
+/**
+ * link_stats - print link statistics
+ * @name: link name
+ * @buf: print buffer area
+ * @buf_size: size of print buffer area
+ * 
+ * Returns length of print buffer data string (or 0 if error)
+ */
+
+static int link_stats(const char *name, char *buf, const u32 buf_size)
+{
+       struct print_buf pb;
+       struct link *l_ptr; 
+       struct node *node;
+       char *status;
+       u32 profile_total = 0;
+
+       if (!strcmp(name, bc_link_name))
+               return bclink_stats(buf, buf_size);
+
+       printbuf_init(&pb, buf, buf_size);
+
+       read_lock_bh(&net_lock);
+       l_ptr = link_find_link(name, &node); 
+       if (!l_ptr) {
+               read_unlock_bh(&net_lock);
+               return 0;
+       }
+       node_lock(node);
+
+       if (link_is_active(l_ptr))
+               status = "ACTIVE";
+       else if (link_is_up(l_ptr))
+               status = "STANDBY";
+       else
+               status = "DEFUNCT";
+       tipc_printf(&pb, "Link <%s>\n"
+                        "  %s  MTU:%u  Priority:%u  Tolerance:%u ms"
+                        "  Window:%u packets\n", 
+                   l_ptr->name, status, link_max_pkt(l_ptr), 
+                   l_ptr->priority, l_ptr->tolerance, l_ptr->queue_limit[0]);
+       tipc_printf(&pb, "  RX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+                   l_ptr->next_in_no - l_ptr->stats.recv_info,
+                   l_ptr->stats.recv_fragments,
+                   l_ptr->stats.recv_fragmented,
+                   l_ptr->stats.recv_bundles,
+                   l_ptr->stats.recv_bundled);
+       tipc_printf(&pb, "  TX packets:%u fragments:%u/%u bundles:%u/%u\n", 
+                   l_ptr->next_out_no - l_ptr->stats.sent_info,
+                   l_ptr->stats.sent_fragments,
+                   l_ptr->stats.sent_fragmented, 
+                   l_ptr->stats.sent_bundles,
+                   l_ptr->stats.sent_bundled);
+       profile_total = l_ptr->stats.msg_length_counts;
+       if (!profile_total)
+               profile_total = 1;
+       tipc_printf(&pb, "  TX profile sample:%u packets  average:%u octets\n"
+                        "  0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
+                        "-16354:%u%% -32768:%u%% -66000:%u%%\n",
+                   l_ptr->stats.msg_length_counts,
+                   l_ptr->stats.msg_lengths_total / profile_total,
+                   percent(l_ptr->stats.msg_length_profile[0], profile_total),
+                   percent(l_ptr->stats.msg_length_profile[1], profile_total),
+                   percent(l_ptr->stats.msg_length_profile[2], profile_total),
+                   percent(l_ptr->stats.msg_length_profile[3], profile_total),
+                   percent(l_ptr->stats.msg_length_profile[4], profile_total),
+                   percent(l_ptr->stats.msg_length_profile[5], profile_total),
+                   percent(l_ptr->stats.msg_length_profile[6], profile_total));
+       tipc_printf(&pb, "  RX states:%u probes:%u naks:%u defs:%u dups:%u\n", 
+                   l_ptr->stats.recv_states,
+                   l_ptr->stats.recv_probes,
+                   l_ptr->stats.recv_nacks,
+                   l_ptr->stats.deferred_recv, 
+                   l_ptr->stats.duplicates);
+       tipc_printf(&pb, "  TX states:%u probes:%u naks:%u acks:%u dups:%u\n", 
+                   l_ptr->stats.sent_states, 
+                   l_ptr->stats.sent_probes, 
+                   l_ptr->stats.sent_nacks, 
+                   l_ptr->stats.sent_acks, 
+                   l_ptr->stats.retransmitted);
+       tipc_printf(&pb, "  Congestion bearer:%u link:%u  Send queue max:%u avg:%u\n",
+                   l_ptr->stats.bearer_congs,
+                   l_ptr->stats.link_congs, 
+                   l_ptr->stats.max_queue_sz,
+                   l_ptr->stats.queue_sz_counts
+                   ? (l_ptr->stats.accu_queue_sz / l_ptr->stats.queue_sz_counts)
+                   : 0);
+
+       node_unlock(node);
+       read_unlock_bh(&net_lock);
+       return printbuf_validate(&pb);
+}
+
+#define MAX_LINK_STATS_INFO 2000
+
+struct sk_buff *link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space)
+{
+       struct sk_buff *buf;
+       struct tlv_desc *rep_tlv;
+       int str_len;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       buf = cfg_reply_alloc(TLV_SPACE(MAX_LINK_STATS_INFO));
+       if (!buf)
+               return NULL;
+
+       rep_tlv = (struct tlv_desc *)buf->data;
+
+       str_len = link_stats((char *)TLV_DATA(req_tlv_area),
+                            (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO);
+       if (!str_len) {
+               buf_discard(buf);
+               return cfg_reply_error_string("link not found");
+       }
+
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
+#if 0
+int link_control(const char *name, u32 op, u32 val)
+{
+       int res = -EINVAL;
+       struct link *l_ptr;
+       u32 bearer_id;
+       struct node * node;
+       u32 a;
+
+       a = link_name2addr(name, &bearer_id);
+       read_lock_bh(&net_lock);
+       node = node_find(a);
+       if (node) {
+               node_lock(node);
+               l_ptr = node->links[bearer_id];
+               if (l_ptr) {
+                       if (op == TIPC_REMOVE_LINK) {
+                               struct bearer *b_ptr = l_ptr->b_ptr;
+                               spin_lock_bh(&b_ptr->publ.lock);
+                               link_delete(l_ptr);
+                               spin_unlock_bh(&b_ptr->publ.lock);
+                       }
+                       if (op == TIPC_CMD_BLOCK_LINK) {
+                               link_reset(l_ptr);
+                               l_ptr->blocked = 1;
+                       }
+                       if (op == TIPC_CMD_UNBLOCK_LINK) {
+                               l_ptr->blocked = 0;
+                       }
+                       res = TIPC_OK;
+               }
+               node_unlock(node);
+       }
+       read_unlock_bh(&net_lock);
+       return res;
+}
+#endif
+
+/**
+ * link_get_max_pkt - get maximum packet size to use when sending to destination
+ * @dest: network address of destination node
+ * @selector: used to select from set of active links
+ * 
+ * If no active link can be found, uses default maximum packet size.
+ */
+
+u32 link_get_max_pkt(u32 dest, u32 selector)
+{
+       struct node *n_ptr;
+       struct link *l_ptr;
+       u32 res = MAX_PKT_DEFAULT;
+       
+       if (dest == tipc_own_addr)
+               return MAX_MSG_SIZE;
+
+       read_lock_bh(&net_lock);        
+       n_ptr = node_select(dest, selector);
+       if (n_ptr) {
+               node_lock(n_ptr);
+               l_ptr = n_ptr->active_links[selector & 1];
+               if (l_ptr)
+                       res = link_max_pkt(l_ptr);
+               node_unlock(n_ptr);
+       }
+       read_unlock_bh(&net_lock);       
+       return res;
+}
+
+#if 0
+static void link_dump_rec_queue(struct link *l_ptr)
+{
+       struct sk_buff *crs;
+
+       if (!l_ptr->oldest_deferred_in) {
+               info("Reception queue empty\n");
+               return;
+       }
+       info("Contents of Reception queue:\n");
+       crs = l_ptr->oldest_deferred_in;
+       while (crs) {
+               if (crs->data == (void *)0x0000a3a3) {
+                       info("buffer %x invalid\n", crs);
+                       return;
+               }
+               msg_dbg(buf_msg(crs), "In rec queue: \n");
+               crs = crs->next;
+       }
+}
+#endif
+
+static void link_dump_send_queue(struct link *l_ptr)
+{
+       if (l_ptr->next_out) {
+               info("\nContents of unsent queue:\n");
+               dbg_print_buf_chain(l_ptr->next_out);
+       }
+       info("\nContents of send queue:\n");
+       if (l_ptr->first_out) {
+               dbg_print_buf_chain(l_ptr->first_out);
+       }
+       info("Empty send queue\n");
+}
+
+static void link_print(struct link *l_ptr, struct print_buf *buf,
+                      const char *str)
+{
+       tipc_printf(buf, str);
+       if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr))
+               return;
+       tipc_printf(buf, "Link %x<%s>:",
+                   l_ptr->addr, l_ptr->b_ptr->publ.name);
+       tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no));
+       tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no));
+       tipc_printf(buf, "SQUE");
+       if (l_ptr->first_out) {
+               tipc_printf(buf, "[%u..", msg_seqno(buf_msg(l_ptr->first_out)));
+               if (l_ptr->next_out)
+                       tipc_printf(buf, "%u..",
+                                   msg_seqno(buf_msg(l_ptr->next_out)));
+               tipc_printf(buf, "%u]",
+                           msg_seqno(buf_msg
+                                     (l_ptr->last_out)), l_ptr->out_queue_size);
+               if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) - 
+                        msg_seqno(buf_msg(l_ptr->first_out))) 
+                    != (l_ptr->out_queue_size - 1))
+                   || (l_ptr->last_out->next != 0)) {
+                       tipc_printf(buf, "\nSend queue inconsistency\n");
+                       tipc_printf(buf, "first_out= %x ", l_ptr->first_out);
+                       tipc_printf(buf, "next_out= %x ", l_ptr->next_out);
+                       tipc_printf(buf, "last_out= %x ", l_ptr->last_out);
+                       link_dump_send_queue(l_ptr);
+               }
+       } else
+               tipc_printf(buf, "[]");
+       tipc_printf(buf, "SQSIZ(%u)", l_ptr->out_queue_size);
+       if (l_ptr->oldest_deferred_in) {
+               u32 o = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
+               u32 n = msg_seqno(buf_msg(l_ptr->newest_deferred_in));
+               tipc_printf(buf, ":RQUE[%u..%u]", o, n);
+               if (l_ptr->deferred_inqueue_sz != mod((n + 1) - o)) {
+                       tipc_printf(buf, ":RQSIZ(%u)",
+                                   l_ptr->deferred_inqueue_sz);
+               }
+       }
+       if (link_working_unknown(l_ptr))
+               tipc_printf(buf, ":WU");
+       if (link_reset_reset(l_ptr))
+               tipc_printf(buf, ":RR");
+       if (link_reset_unknown(l_ptr))
+               tipc_printf(buf, ":RU");
+       if (link_working_working(l_ptr))
+               tipc_printf(buf, ":WW");
+       tipc_printf(buf, "\n");
+}
+
diff --git a/net/tipc/link.h b/net/tipc/link.h
new file mode 100644 (file)
index 0000000..c2553f0
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * net/tipc/link.h: Include file for TIPC link code
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_LINK_H
+#define _TIPC_LINK_H
+
+#include "dbg.h"
+#include "msg.h"
+#include "bearer.h"
+#include "node.h"
+
+#define PUSH_FAILED   1
+#define PUSH_FINISHED 2
+
+/* 
+ * Link states 
+ */
+
+#define WORKING_WORKING 560810u
+#define WORKING_UNKNOWN 560811u
+#define RESET_UNKNOWN   560812u
+#define RESET_RESET     560813u
+
+/* 
+ * Starting value for maximum packet size negotiation on unicast links
+ * (unless bearer MTU is less)
+ */
+
+#define MAX_PKT_DEFAULT 1500
+
+/**
+ * struct link - TIPC link data structure
+ * @addr: network address of link's peer node
+ * @name: link name character string
+ * @media_addr: media address to use when sending messages over link
+ * @timer: link timer
+ * @owner: pointer to peer node
+ * @link_list: adjacent links in bearer's list of links
+ * @started: indicates if link has been started
+ * @checkpoint: reference point for triggering link continuity checking
+ * @peer_session: link session # being used by peer end of link
+ * @peer_bearer_id: bearer id used by link's peer endpoint
+ * @b_ptr: pointer to bearer used by link
+ * @tolerance: minimum link continuity loss needed to reset link [in ms] 
+ * @continuity_interval: link continuity testing interval [in ms]
+ * @abort_limit: # of unacknowledged continuity probes needed to reset link
+ * @state: current state of link FSM
+ * @blocked: indicates if link has been administratively blocked
+ * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state
+ * @proto_msg: template for control messages generated by link
+ * @pmsg: convenience pointer to "proto_msg" field
+ * @priority: current link priority
+ * @queue_limit: outbound message queue congestion thresholds (indexed by user)
+ * @exp_msg_count: # of tunnelled messages expected during link changeover
+ * @reset_checkpoint: seq # of last acknowledged message at time of link reset
+ * @max_pkt: current maximum packet size for this link
+ * @max_pkt_target: desired maximum packet size for this link
+ * @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target)
+ * @out_queue_size: # of messages in outbound message queue
+ * @first_out: ptr to first outbound message in queue
+ * @last_out: ptr to last outbound message in queue
+ * @next_out_no: next sequence number to use for outbound messages
+ * @last_retransmitted: sequence number of most recently retransmitted message
+ * @stale_count: # of identical retransmit requests made by peer
+ * @next_in_no: next sequence number to expect for inbound messages
+ * @deferred_inqueue_sz: # of messages in inbound message queue
+ * @oldest_deferred_in: ptr to first inbound message in queue
+ * @newest_deferred_in: ptr to last inbound message in queue
+ * @unacked_window: # of inbound messages rx'd without ack'ing back to peer
+ * @proto_msg_queue: ptr to (single) outbound control message
+ * @retransm_queue_size: number of messages to retransmit
+ * @retransm_queue_head: sequence number of first message to retransmit
+ * @next_out: ptr to first unsent outbound message in queue
+ * @waiting_ports: linked list of ports waiting for link congestion to abate
+ * @long_msg_seq_no: next identifier to use for outbound fragmented messages
+ * @defragm_buf: list of partially reassembled inbound message fragments
+ * @stats: collects statistics regarding link activity
+ * @print_buf: print buffer used to log link activity
+ */
+struct link {
+       u32 addr;
+       char name[TIPC_MAX_LINK_NAME];
+       struct tipc_media_addr media_addr;
+       struct timer_list timer;
+       struct node *owner;
+       struct list_head link_list;
+
+       /* Management and link supervision data */
+       int started;
+       u32 checkpoint;
+       u32 peer_session;
+       u32 peer_bearer_id;
+       struct bearer *b_ptr;
+       u32 tolerance;
+       u32 continuity_interval;
+       u32 abort_limit;
+       int state;
+       int blocked;
+       u32 fsm_msg_cnt;
+       struct {
+               unchar hdr[INT_H_SIZE];
+               unchar body[TIPC_MAX_IF_NAME];
+       } proto_msg;
+       struct tipc_msg *pmsg;
+       u32 priority;
+       u32 queue_limit[15];    /* queue_limit[0]==window limit */
+
+       /* Changeover */
+       u32 exp_msg_count;
+       u32 reset_checkpoint;
+
+        /* Max packet negotiation */
+        u32 max_pkt;
+        u32 max_pkt_target;
+        u32 max_pkt_probes;
+
+       /* Sending */
+       u32 out_queue_size;
+       struct sk_buff *first_out;
+       struct sk_buff *last_out;
+       u32 next_out_no;
+        u32 last_retransmitted;
+        u32 stale_count;
+
+       /* Reception */
+       u32 next_in_no;
+       u32 deferred_inqueue_sz;
+       struct sk_buff *oldest_deferred_in;
+       struct sk_buff *newest_deferred_in;
+       u32 unacked_window;
+
+       /* Congestion handling */
+       struct sk_buff *proto_msg_queue;
+       u32 retransm_queue_size;
+       u32 retransm_queue_head;
+       struct sk_buff *next_out;
+       struct list_head waiting_ports;
+
+       /* Fragmentation/defragmentation */
+       u32 long_msg_seq_no;
+       struct sk_buff *defragm_buf;
+
+        /* Statistics */
+       struct {
+               u32 sent_info;          /* used in counting # sent packets */
+               u32 recv_info;          /* used in counting # recv'd packets */
+               u32 sent_states;
+               u32 recv_states;
+               u32 sent_probes;
+               u32 recv_probes;
+               u32 sent_nacks;
+               u32 recv_nacks;
+               u32 sent_acks;
+               u32 sent_bundled;
+               u32 sent_bundles;
+               u32 recv_bundled;
+               u32 recv_bundles;
+               u32 retransmitted;
+               u32 sent_fragmented;
+               u32 sent_fragments;
+               u32 recv_fragmented;
+               u32 recv_fragments;
+               u32 link_congs;         /* # port sends blocked by congestion */
+               u32 bearer_congs;
+               u32 deferred_recv;
+               u32 duplicates;
+
+               /* for statistical profiling of send queue size */
+
+               u32 max_queue_sz;
+               u32 accu_queue_sz;
+               u32 queue_sz_counts;
+
+               /* for statistical profiling of message lengths */
+
+               u32 msg_length_counts;
+               u32 msg_lengths_total;
+               u32 msg_length_profile[7];
+#if 0
+               u32 sent_tunneled;
+               u32 recv_tunneled;
+#endif
+       } stats;
+
+       struct print_buf print_buf;
+};
+
+struct port;
+
+struct link *link_create(struct bearer *b_ptr, const u32 peer,
+                        const struct tipc_media_addr *media_addr);
+void link_delete(struct link *l_ptr);
+void link_changeover(struct link *l_ptr);
+void link_send_duplicate(struct link *l_ptr, struct link *dest);
+void link_reset_fragments(struct link *l_ptr);
+int link_is_up(struct link *l_ptr);
+int link_is_active(struct link *l_ptr);
+void link_start(struct link *l_ptr);
+u32 link_push_packet(struct link *l_ptr);
+void link_stop(struct link *l_ptr);
+struct sk_buff *link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd);
+struct sk_buff *link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space);
+void link_reset(struct link *l_ptr);
+int link_send(struct sk_buff *buf, u32 dest, u32 selector);
+int link_send_buf(struct link *l_ptr, struct sk_buff *buf);
+u32 link_get_max_pkt(u32 dest,u32 selector);
+int link_send_sections_fast(struct port* sender, 
+                           struct iovec const *msg_sect,
+                           const u32 num_sect, 
+                           u32 destnode);
+
+int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf);
+void link_tunnel(struct link *l_ptr, struct tipc_msg *tnl_hdr,
+                struct tipc_msg *msg, u32 selector);
+void link_recv_bundle(struct sk_buff *buf);
+int  link_recv_fragment(struct sk_buff **pending,
+                       struct sk_buff **fb,
+                       struct tipc_msg **msg);
+void link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int prob, u32 gap, 
+                        u32 tolerance, u32 priority, u32 acked_mtu);
+void link_push_queue(struct link *l_ptr);
+u32 link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
+                  struct sk_buff *buf);
+void link_wakeup_ports(struct link *l_ptr, int all);
+void link_set_queue_limits(struct link *l_ptr, u32 window);
+void link_retransmit(struct link *l_ptr, struct sk_buff *start, u32 retransmits);
+
+/*
+ * Link sequence number manipulation routines (uses modulo 2**16 arithmetic)
+ */
+
+static inline u32 mod(u32 x)
+{
+       return x & 0xffffu;
+}
+
+static inline int between(u32 lower, u32 upper, u32 n)
+{
+       if ((lower < n) && (n < upper))
+               return 1;
+       if ((upper < lower) && ((n > lower) || (n < upper)))
+               return 1;
+       return 0;
+}
+
+static inline int less_eq(u32 left, u32 right)
+{
+       return (mod(right - left) < 32768u);
+}
+
+static inline int less(u32 left, u32 right)
+{
+       return (less_eq(left, right) && (mod(right) != mod(left)));
+}
+
+static inline u32 lesser(u32 left, u32 right)
+{
+       return less_eq(left, right) ? left : right;
+}
+
+#endif
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
new file mode 100644 (file)
index 0000000..03dbc55
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * net/tipc/msg.c: TIPC message header routines
+ *     
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "addr.h"
+#include "dbg.h"
+#include "msg.h"
+#include "bearer.h"
+
+
+void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
+{
+       memcpy(&((int *)m)[5], a, sizeof(*a));
+}
+
+void msg_get_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
+{
+       memcpy(a, &((int*)m)[5], sizeof(*a));
+}
+
+
+void msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str)
+{
+       u32 usr = msg_user(msg);
+       tipc_printf(buf, str);
+
+       switch (usr) {
+       case MSG_BUNDLER:
+               tipc_printf(buf, "BNDL::");
+               tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg));
+               break;
+       case BCAST_PROTOCOL:
+               tipc_printf(buf, "BCASTP::");
+               break;
+       case MSG_FRAGMENTER:
+               tipc_printf(buf, "FRAGM::");
+               switch (msg_type(msg)) {
+               case FIRST_FRAGMENT:
+                       tipc_printf(buf, "FIRST:");
+                       break;
+               case FRAGMENT:
+                       tipc_printf(buf, "BODY:");
+                       break;
+               case LAST_FRAGMENT:
+                       tipc_printf(buf, "LAST:");
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
+
+               }
+               tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg),
+                           msg_fragm_no(msg));
+               break;
+       case DATA_LOW:
+       case DATA_MEDIUM:
+       case DATA_HIGH:
+       case DATA_CRITICAL:
+               tipc_printf(buf, "DAT%u:", msg_user(msg));
+               if (msg_short(msg)) {
+                       tipc_printf(buf, "CON:");
+                       break;
+               }
+               switch (msg_type(msg)) {
+               case TIPC_CONN_MSG:
+                       tipc_printf(buf, "CON:");
+                       break;
+               case TIPC_MCAST_MSG:
+                       tipc_printf(buf, "MCST:");
+                       break;
+               case TIPC_NAMED_MSG:
+                       tipc_printf(buf, "NAM:");
+                       break;
+               case TIPC_DIRECT_MSG:
+                       tipc_printf(buf, "DIR:");
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg));
+               }
+               if (msg_routed(msg) && !msg_non_seq(msg))
+                       tipc_printf(buf, "ROUT:");
+               if (msg_reroute_cnt(msg))
+                       tipc_printf(buf, "REROUTED(%u):",
+                                   msg_reroute_cnt(msg));
+               break;
+       case NAME_DISTRIBUTOR:
+               tipc_printf(buf, "NMD::");
+               switch (msg_type(msg)) {
+               case PUBLICATION:
+                       tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20);  /* Items */
+                       break;
+               case WITHDRAWAL:
+                       tipc_printf(buf, "WDRW:");
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
+               }
+               if (msg_routed(msg))
+                       tipc_printf(buf, "ROUT:");
+               if (msg_reroute_cnt(msg))
+                       tipc_printf(buf, "REROUTED(%u):",
+                                   msg_reroute_cnt(msg));
+               break;
+       case CONN_MANAGER:
+               tipc_printf(buf, "CONN_MNG:");
+               switch (msg_type(msg)) {
+               case CONN_PROBE:
+                       tipc_printf(buf, "PROBE:");
+                       break;
+               case CONN_PROBE_REPLY:
+                       tipc_printf(buf, "PROBE_REPLY:");
+                       break;
+               case CONN_ACK:
+                       tipc_printf(buf, "CONN_ACK:");
+                       tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg));
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+               }
+               if (msg_routed(msg))
+                       tipc_printf(buf, "ROUT:");
+               if (msg_reroute_cnt(msg))
+                       tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg));
+               break;
+       case LINK_PROTOCOL:
+               tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg));
+               switch (msg_type(msg)) {
+               case STATE_MSG:
+                       tipc_printf(buf, "STATE:");
+                       tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :"");
+                       tipc_printf(buf, "NXS(%u):",msg_next_sent(msg));
+                       tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg));
+                       tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg));
+                       break;
+               case RESET_MSG:
+                       tipc_printf(buf, "RESET:");
+                       if (msg_size(msg) != msg_hdr_sz(msg))
+                               tipc_printf(buf, "BEAR:%s:",msg_data(msg));
+                       break;
+               case ACTIVATE_MSG:
+                       tipc_printf(buf, "ACTIVATE:");
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+               }
+               tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg));
+               tipc_printf(buf, "SESS(%u):",msg_session(msg));
+               break;
+       case CHANGEOVER_PROTOCOL:
+               tipc_printf(buf, "TUNL:");
+               switch (msg_type(msg)) {
+               case DUPLICATE_MSG:
+                       tipc_printf(buf, "DUPL:");
+                       break;
+               case ORIGINAL_MSG:
+                       tipc_printf(buf, "ORIG:");
+                       tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg));
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+               }
+               break;
+       case ROUTE_DISTRIBUTOR:
+               tipc_printf(buf, "ROUTING_MNG:");
+               switch (msg_type(msg)) {
+               case EXT_ROUTING_TABLE:
+                       tipc_printf(buf, "EXT_TBL:");
+                       tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+                       break;
+               case LOCAL_ROUTING_TABLE:
+                       tipc_printf(buf, "LOCAL_TBL:");
+                       tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+                       break;
+               case SLAVE_ROUTING_TABLE:
+                       tipc_printf(buf, "DP_TBL:");
+                       tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+                       break;
+               case ROUTE_ADDITION:
+                       tipc_printf(buf, "ADD:");
+                       tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+                       break;
+               case ROUTE_REMOVAL:
+                       tipc_printf(buf, "REMOVE:");
+                       tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
+               }
+               break;
+       case LINK_CONFIG:
+               tipc_printf(buf, "CFG:");
+               switch (msg_type(msg)) {
+               case DSC_REQ_MSG:
+                       tipc_printf(buf, "DSC_REQ:");
+                       break;
+               case DSC_RESP_MSG:
+                       tipc_printf(buf, "DSC_RESP:");
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg));
+                       break;
+               }
+               break;
+       default:
+               tipc_printf(buf, "UNKNOWN USER:");
+       }
+
+       switch (usr) {
+       case CONN_MANAGER:
+       case NAME_DISTRIBUTOR:
+       case DATA_LOW:
+       case DATA_MEDIUM:
+       case DATA_HIGH:
+       case DATA_CRITICAL:
+               if (msg_short(msg))
+                       break;  /* No error */
+               switch (msg_errcode(msg)) {
+               case TIPC_OK:
+                       break;
+               case TIPC_ERR_NO_NAME:
+                       tipc_printf(buf, "NO_NAME:");
+                       break;
+               case TIPC_ERR_NO_PORT:
+                       tipc_printf(buf, "NO_PORT:");
+                       break;
+               case TIPC_ERR_NO_NODE:
+                       tipc_printf(buf, "NO_PROC:");
+                       break;
+               case TIPC_ERR_OVERLOAD:
+                       tipc_printf(buf, "OVERLOAD:");
+                       break;
+               case TIPC_CONN_SHUTDOWN:
+                       tipc_printf(buf, "SHUTDOWN:");
+                       break;
+               default:
+                       tipc_printf(buf, "UNKNOWN ERROR(%x):",
+                                   msg_errcode(msg));
+               }
+       default:{}
+       }
+
+       tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg));
+       tipc_printf(buf, "SZ(%u):", msg_size(msg));
+       tipc_printf(buf, "SQNO(%u):", msg_seqno(msg));
+
+       if (msg_non_seq(msg))
+               tipc_printf(buf, "NOSEQ:");
+       else {
+               tipc_printf(buf, "ACK(%u):", msg_ack(msg));
+       }
+       tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg));
+       tipc_printf(buf, "PRND(%x)", msg_prevnode(msg));
+
+       if (msg_isdata(msg)) {
+               if (msg_named(msg)) {
+                       tipc_printf(buf, "NTYP(%u):", msg_nametype(msg));
+                       tipc_printf(buf, "NINST(%u)", msg_nameinst(msg));
+               }
+       }
+
+       if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) &&
+           (usr != MSG_BUNDLER)) {
+               if (!msg_short(msg)) {
+                       tipc_printf(buf, ":ORIG(%x:%u):",
+                                   msg_orignode(msg), msg_origport(msg));
+                       tipc_printf(buf, ":DEST(%x:%u):",
+                                   msg_destnode(msg), msg_destport(msg));
+               } else {
+                       tipc_printf(buf, ":OPRT(%u):", msg_origport(msg));
+                       tipc_printf(buf, ":DPRT(%u):", msg_destport(msg));
+               }
+               if (msg_routed(msg) && !msg_non_seq(msg))
+                       tipc_printf(buf, ":TSEQN(%u)", msg_transp_seqno(msg));
+       }
+       if (msg_user(msg) == NAME_DISTRIBUTOR) {
+               tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg));
+               tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg));
+               if (msg_routed(msg)) {
+                       tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg));
+               }
+       }
+
+       if (msg_user(msg) ==  LINK_CONFIG) {
+               u32* raw = (u32*)msg;
+               struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5];
+               tipc_printf(buf, ":REQL(%u):", msg_req_links(msg));
+               tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg));
+               tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg));
+               media_addr_printf(buf, orig);
+       }
+       if (msg_user(msg) == BCAST_PROTOCOL) {
+               tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg));
+               tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg));
+       }
+       tipc_printf(buf, "\n");
+       if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
+               msg_print(buf,msg_get_wrapped(msg),"      /");
+       }
+       if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
+               msg_print(buf,msg_get_wrapped(msg),"      /");
+       }
+}
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
new file mode 100644 (file)
index 0000000..662c818
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * net/tipc/msg.h: Include file for TIPC message header routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_MSG_H
+#define _TIPC_MSG_H
+
+#include <net/tipc/tipc_msg.h>
+
+#define TIPC_VERSION              2
+#define DATA_LOW                  TIPC_LOW_IMPORTANCE
+#define DATA_MEDIUM               TIPC_MEDIUM_IMPORTANCE
+#define DATA_HIGH                 TIPC_HIGH_IMPORTANCE
+#define DATA_CRITICAL             TIPC_CRITICAL_IMPORTANCE
+#define SHORT_H_SIZE              24   /* Connected,in cluster */
+#define DIR_MSG_H_SIZE            32   /* Directly addressed messages */
+#define CONN_MSG_H_SIZE           36   /* Routed connected msgs*/
+#define LONG_H_SIZE               40   /* Named Messages */
+#define MCAST_H_SIZE              44   /* Multicast messages */
+#define MAX_H_SIZE                60   /* Inclusive full options */
+#define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
+#define LINK_CONFIG               13
+
+
+/*
+               TIPC user data message header format, version 2
+               
+       - Fundamental definitions available to privileged TIPC users
+         are located in tipc_msg.h.
+       - Remaining definitions available to TIPC internal users appear below. 
+*/
+
+
+static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val)
+{
+       m->hdr[w] = htonl(val);
+}
+
+static inline void msg_set_bits(struct tipc_msg *m, u32 w,
+                               u32 pos, u32 mask, u32 val)
+{
+       u32 word = msg_word(m,w) & ~(mask << pos);
+       msg_set_word(m, w, (word |= (val << pos)));
+}
+
+/* 
+ * Word 0
+ */
+
+static inline u32 msg_version(struct tipc_msg *m)
+{
+       return msg_bits(m, 0, 29, 7);
+}
+
+static inline void msg_set_version(struct tipc_msg *m) 
+{
+       msg_set_bits(m, 0, 29, 0xf, TIPC_VERSION);
+}
+
+static inline u32 msg_user(struct tipc_msg *m)
+{
+       return msg_bits(m, 0, 25, 0xf);
+}
+
+static inline u32 msg_isdata(struct tipc_msg *m)
+{
+       return (msg_user(m) <= DATA_CRITICAL);
+}
+
+static inline void msg_set_user(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 0, 25, 0xf, n);
+}
+
+static inline void msg_set_importance(struct tipc_msg *m, u32 i) 
+{
+       msg_set_user(m, i);
+}
+
+static inline void msg_set_hdr_sz(struct tipc_msg *m,u32 n) 
+{
+       msg_set_bits(m, 0, 21, 0xf, n>>2);
+}
+
+static inline int msg_non_seq(struct tipc_msg *m) 
+{
+       return msg_bits(m, 0, 20, 1);
+}
+
+static inline void msg_set_non_seq(struct tipc_msg *m) 
+{
+       msg_set_bits(m, 0, 20, 1, 1);
+}
+
+static inline int msg_dest_droppable(struct tipc_msg *m) 
+{
+       return msg_bits(m, 0, 19, 1);
+}
+
+static inline void msg_set_dest_droppable(struct tipc_msg *m, u32 d) 
+{
+       msg_set_bits(m, 0, 19, 1, d);
+}
+
+static inline int msg_src_droppable(struct tipc_msg *m) 
+{
+       return msg_bits(m, 0, 18, 1);
+}
+
+static inline void msg_set_src_droppable(struct tipc_msg *m, u32 d) 
+{
+       msg_set_bits(m, 0, 18, 1, d);
+}
+
+static inline void msg_set_size(struct tipc_msg *m, u32 sz)
+{
+       m->hdr[0] = htonl((msg_word(m, 0) & ~0x1ffff) | sz);
+}
+
+
+/* 
+ * Word 1
+ */
+
+static inline void msg_set_type(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 1, 29, 0x7, n);
+}
+
+static inline void msg_set_errcode(struct tipc_msg *m, u32 err) 
+{
+       msg_set_bits(m, 1, 25, 0xf, err);
+}
+
+static inline u32 msg_reroute_cnt(struct tipc_msg *m) 
+{
+       return msg_bits(m, 1, 21, 0xf);
+}
+
+static inline void msg_incr_reroute_cnt(struct tipc_msg *m) 
+{
+       msg_set_bits(m, 1, 21, 0xf, msg_reroute_cnt(m) + 1);
+}
+
+static inline void msg_reset_reroute_cnt(struct tipc_msg *m) 
+{
+       msg_set_bits(m, 1, 21, 0xf, 0);
+}
+
+static inline u32 msg_lookup_scope(struct tipc_msg *m)
+{
+       return msg_bits(m, 1, 19, 0x3);
+}
+
+static inline void msg_set_lookup_scope(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 1, 19, 0x3, n);
+}
+
+static inline void msg_set_options(struct tipc_msg *m, const char *opt, u32 sz) 
+{
+       u32 hsz = msg_hdr_sz(m);
+       char *to = (char *)&m->hdr[hsz/4];
+
+       if ((hsz < DIR_MSG_H_SIZE) || ((hsz + sz) > MAX_H_SIZE))
+               return;
+       msg_set_bits(m, 1, 16, 0x7, (hsz - 28)/4);
+       msg_set_hdr_sz(m, hsz + sz);
+       memcpy(to, opt, sz);
+}
+
+static inline u32 msg_bcast_ack(struct tipc_msg *m)
+{
+       return msg_bits(m, 1, 0, 0xffff);
+}
+
+static inline void msg_set_bcast_ack(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 1, 0, 0xffff, n);
+}
+
+
+/* 
+ * Word 2
+ */
+
+static inline u32 msg_ack(struct tipc_msg *m)
+{
+       return msg_bits(m, 2, 16, 0xffff);
+}
+
+static inline void msg_set_ack(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 2, 16, 0xffff, n);
+}
+
+static inline u32 msg_seqno(struct tipc_msg *m)
+{
+       return msg_bits(m, 2, 0, 0xffff);
+}
+
+static inline void msg_set_seqno(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 2, 0, 0xffff, n);
+}
+
+
+/* 
+ * Words 3-10
+ */
+
+
+static inline void msg_set_prevnode(struct tipc_msg *m, u32 a) 
+{
+       msg_set_word(m, 3, a);
+}
+
+static inline void msg_set_origport(struct tipc_msg *m, u32 p) 
+{
+       msg_set_word(m, 4, p);
+}
+
+static inline void msg_set_destport(struct tipc_msg *m, u32 p) 
+{
+       msg_set_word(m, 5, p);
+}
+
+static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p) 
+{
+       msg_set_word(m, 5, p);
+}
+
+static inline void msg_set_orignode(struct tipc_msg *m, u32 a) 
+{
+       msg_set_word(m, 6, a);
+}
+
+static inline void msg_set_destnode(struct tipc_msg *m, u32 a) 
+{
+       msg_set_word(m, 7, a);
+}
+
+static inline int msg_is_dest(struct tipc_msg *m, u32 d) 
+{
+       return(msg_short(m) || (msg_destnode(m) == d));
+}
+
+static inline u32 msg_routed(struct tipc_msg *m)
+{
+       if (likely(msg_short(m)))
+               return 0;
+       return(msg_destnode(m) ^ msg_orignode(m)) >> 11;
+}
+
+static inline void msg_set_nametype(struct tipc_msg *m, u32 n) 
+{
+       msg_set_word(m, 8, n);
+}
+
+static inline u32 msg_transp_seqno(struct tipc_msg *m)
+{
+       return msg_word(m, 8);
+}
+
+static inline void msg_set_timestamp(struct tipc_msg *m, u32 n)
+{
+       msg_set_word(m, 8, n);
+}
+
+static inline u32 msg_timestamp(struct tipc_msg *m)
+{
+       return msg_word(m, 8);
+}
+
+static inline void msg_set_transp_seqno(struct tipc_msg *m, u32 n)
+{
+       msg_set_word(m, 8, n);
+}
+
+static inline void msg_set_namelower(struct tipc_msg *m, u32 n) 
+{
+       msg_set_word(m, 9, n);
+}
+
+static inline void msg_set_nameinst(struct tipc_msg *m, u32 n) 
+{
+       msg_set_namelower(m, n);
+}
+
+static inline void msg_set_nameupper(struct tipc_msg *m, u32 n) 
+{
+       msg_set_word(m, 10, n);
+}
+
+static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
+{
+       return (struct tipc_msg *)msg_data(m);
+}
+
+static inline void msg_expand(struct tipc_msg *m, u32 destnode) 
+{
+       if (!msg_short(m))
+               return;
+       msg_set_hdr_sz(m, LONG_H_SIZE);
+       msg_set_orignode(m, msg_prevnode(m));
+       msg_set_destnode(m, destnode);
+       memset(&m->hdr[8], 0, 12);
+}
+
+
+
+/*
+               TIPC internal message header format, version 2
+
+       1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0 
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w0:|vers |msg usr|hdr sz |n|resrv|            packet size          |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w1:|m typ|rsv=0|   sequence gap    |       broadcast ack no        |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w2:| link level ack no/bc_gap_from |     seq no / bcast_gap_to     |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w3:|                       previous node                           |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w4:|  next sent broadcast/fragm no | next sent pkt/ fragm msg no   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w5:|          session no           |rsv=0|r|berid|link prio|netpl|p|
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w6:|                      originating node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w7:|                      destination node                         |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w8:|                   transport sequence number                   |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   w9:|   msg count / bcast tag       |       link tolerance          |
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+      \                                                               \
+      /                     User Specific Data                        /
+      \                                                               \
+      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+      NB: CONN_MANAGER use data message format. LINK_CONFIG has own format.
+*/   
+
+/* 
+ * Internal users
+ */
+
+#define  BCAST_PROTOCOL       5
+#define  MSG_BUNDLER          6
+#define  LINK_PROTOCOL        7
+#define  CONN_MANAGER         8
+#define  ROUTE_DISTRIBUTOR    9
+#define  CHANGEOVER_PROTOCOL  10
+#define  NAME_DISTRIBUTOR     11
+#define  MSG_FRAGMENTER       12
+#define  LINK_CONFIG          13
+#define  INT_H_SIZE           40
+#define  DSC_H_SIZE           40
+
+/* 
+ *  Connection management protocol messages
+ */
+
+#define CONN_PROBE        0
+#define CONN_PROBE_REPLY  1
+#define CONN_ACK          2
+
+/* 
+ * Name distributor messages
+ */
+
+#define PUBLICATION       0
+#define WITHDRAWAL        1
+
+
+/* 
+ * Word 1
+ */
+
+static inline u32 msg_seq_gap(struct tipc_msg *m)
+{
+       return msg_bits(m, 1, 16, 0xff);
+}
+
+static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 1, 16, 0xff, n);
+}
+
+static inline u32 msg_req_links(struct tipc_msg *m)
+{
+       return msg_bits(m, 1, 16, 0xfff);
+}
+
+static inline void msg_set_req_links(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 1, 16, 0xfff, n);
+}
+
+
+/* 
+ * Word 2
+ */
+
+static inline u32 msg_dest_domain(struct tipc_msg *m)
+{
+       return msg_word(m, 2);
+}
+
+static inline void msg_set_dest_domain(struct tipc_msg *m, u32 n) 
+{
+       msg_set_word(m, 2, n);
+}
+
+static inline u32 msg_bcgap_after(struct tipc_msg *m)
+{
+       return msg_bits(m, 2, 16, 0xffff);
+}
+
+static inline void msg_set_bcgap_after(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 2, 16, 0xffff, n);
+}
+
+static inline u32 msg_bcgap_to(struct tipc_msg *m)
+{
+       return msg_bits(m, 2, 0, 0xffff);
+}
+
+static inline void msg_set_bcgap_to(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 2, 0, 0xffff, n);
+}
+
+
+/* 
+ * Word 4
+ */
+
+static inline u32 msg_last_bcast(struct tipc_msg *m)
+{
+       return msg_bits(m, 4, 16, 0xffff);
+}
+
+static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 4, 16, 0xffff, n);
+}
+
+
+static inline u32 msg_fragm_no(struct tipc_msg *m)
+{
+       return msg_bits(m, 4, 16, 0xffff);
+}
+
+static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 4, 16, 0xffff, n);
+}
+
+
+static inline u32 msg_next_sent(struct tipc_msg *m)
+{
+       return msg_bits(m, 4, 0, 0xffff);
+}
+
+static inline void msg_set_next_sent(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 4, 0, 0xffff, n);
+}
+
+
+static inline u32 msg_long_msgno(struct tipc_msg *m)
+{
+       return msg_bits(m, 4, 0, 0xffff);
+}
+
+static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 4, 0, 0xffff, n);
+}
+
+static inline u32 msg_bc_netid(struct tipc_msg *m)
+{
+       return msg_word(m, 4);
+}
+
+static inline void msg_set_bc_netid(struct tipc_msg *m, u32 id)
+{
+       msg_set_word(m, 4, id);
+}
+
+static inline u32 msg_link_selector(struct tipc_msg *m)
+{
+       return msg_bits(m, 4, 0, 1);
+}
+
+static inline void msg_set_link_selector(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 4, 0, 1, (n & 1));
+}
+
+/* 
+ * Word 5
+ */
+
+static inline u32 msg_session(struct tipc_msg *m)
+{
+       return msg_bits(m, 5, 16, 0xffff);
+}
+
+static inline void msg_set_session(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 5, 16, 0xffff, n);
+}
+
+static inline u32 msg_probe(struct tipc_msg *m)
+{
+       return msg_bits(m, 5, 0, 1);
+}
+
+static inline void msg_set_probe(struct tipc_msg *m, u32 val)
+{
+       msg_set_bits(m, 5, 0, 1, (val & 1));
+}
+
+static inline char msg_net_plane(struct tipc_msg *m)
+{
+       return msg_bits(m, 5, 1, 7) + 'A';
+}
+
+static inline void msg_set_net_plane(struct tipc_msg *m, char n)
+{
+       msg_set_bits(m, 5, 1, 7, (n - 'A'));
+}
+
+static inline u32 msg_linkprio(struct tipc_msg *m)
+{
+       return msg_bits(m, 5, 4, 0x1f);
+}
+
+static inline void msg_set_linkprio(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 5, 4, 0x1f, n);
+}
+
+static inline u32 msg_bearer_id(struct tipc_msg *m)
+{
+       return msg_bits(m, 5, 9, 0x7);
+}
+
+static inline void msg_set_bearer_id(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 5, 9, 0x7, n);
+}
+
+static inline u32 msg_redundant_link(struct tipc_msg *m)
+{
+       return msg_bits(m, 5, 12, 0x1);
+}
+
+static inline void msg_set_redundant_link(struct tipc_msg *m)
+{
+       msg_set_bits(m, 5, 12, 0x1, 1);
+}
+
+static inline void msg_clear_redundant_link(struct tipc_msg *m)
+{
+       msg_set_bits(m, 5, 12, 0x1, 0);
+}
+
+
+/* 
+ * Word 9
+ */
+
+static inline u32 msg_msgcnt(struct tipc_msg *m)
+{
+       return msg_bits(m, 9, 16, 0xffff);
+}
+
+static inline void msg_set_msgcnt(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 9, 16, 0xffff, n);
+}
+
+static inline u32 msg_bcast_tag(struct tipc_msg *m)
+{
+       return msg_bits(m, 9, 16, 0xffff);
+}
+
+static inline void msg_set_bcast_tag(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 9, 16, 0xffff, n);
+}
+
+static inline u32 msg_max_pkt(struct tipc_msg *m) 
+{
+       return (msg_bits(m, 9, 16, 0xffff) * 4);
+}
+
+static inline void msg_set_max_pkt(struct tipc_msg *m, u32 n) 
+{
+       msg_set_bits(m, 9, 16, 0xffff, (n / 4));
+}
+
+static inline u32 msg_link_tolerance(struct tipc_msg *m)
+{
+       return msg_bits(m, 9, 0, 0xffff);
+}
+
+static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
+{
+       msg_set_bits(m, 9, 0, 0xffff, n);
+}
+
+/* 
+ * Routing table message data
+ */
+
+
+static inline u32 msg_remote_node(struct tipc_msg *m)
+{
+       return msg_word(m, msg_hdr_sz(m)/4);
+}
+
+static inline void msg_set_remote_node(struct tipc_msg *m, u32 a)
+{
+       msg_set_word(m, msg_hdr_sz(m)/4, a);
+}
+
+static inline int msg_dataoctet(struct tipc_msg *m, u32 pos)
+{
+       return(msg_data(m)[pos + 4] != 0);
+}
+
+static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos)
+{
+       msg_data(m)[pos + 4] = 1;
+}
+
+/* 
+ * Segmentation message types
+ */
+
+#define FIRST_FRAGMENT     0
+#define FRAGMENT           1
+#define LAST_FRAGMENT      2
+
+/* 
+ * Link management protocol message types
+ */
+
+#define STATE_MSG       0
+#define RESET_MSG       1
+#define ACTIVATE_MSG    2
+
+/* 
+ * Changeover tunnel message types
+ */
+#define DUPLICATE_MSG    0
+#define ORIGINAL_MSG     1
+
+/* 
+ * Routing table message types
+ */
+#define EXT_ROUTING_TABLE    0
+#define LOCAL_ROUTING_TABLE  1
+#define SLAVE_ROUTING_TABLE  2
+#define ROUTE_ADDITION       3
+#define ROUTE_REMOVAL        4
+
+/* 
+ * Config protocol message types
+ */
+
+#define DSC_REQ_MSG          0
+#define DSC_RESP_MSG         1
+
+static inline u32 msg_tot_importance(struct tipc_msg *m)
+{
+       if (likely(msg_isdata(m))) {
+               if (likely(msg_orignode(m) == tipc_own_addr))
+                       return msg_importance(m);
+               return msg_importance(m) + 4;
+       }
+       if ((msg_user(m) == MSG_FRAGMENTER)  &&
+           (msg_type(m) == FIRST_FRAGMENT))
+               return msg_importance(msg_get_wrapped(m));
+       return msg_importance(m);
+}
+
+
+static inline void msg_init(struct tipc_msg *m, u32 user, u32 type, 
+                           u32 err, u32 hsize, u32 destnode)
+{
+       memset(m, 0, hsize);
+       msg_set_version(m);
+       msg_set_user(m, user);
+       msg_set_hdr_sz(m, hsize);
+       msg_set_size(m, hsize);
+       msg_set_prevnode(m, tipc_own_addr);
+       msg_set_type(m, type);
+       msg_set_errcode(m, err);
+       if (!msg_short(m)) {
+               msg_set_orignode(m, tipc_own_addr);
+               msg_set_destnode(m, destnode);
+       }
+}
+
+/** 
+ * msg_calc_data_size - determine total data size for message
+ */
+
+static inline int msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
+{
+       int dsz = 0;
+       int i;
+
+       for (i = 0; i < num_sect; i++)
+               dsz += msg_sect[i].iov_len;
+       return dsz;
+}
+
+/** 
+ * msg_build - create message using specified header and data
+ * 
+ * Note: Caller must not hold any locks in case copy_from_user() is interrupted!
+ * 
+ * Returns message data size or errno
+ */
+
+static inline int msg_build(struct tipc_msg *hdr, 
+                           struct iovec const *msg_sect, u32 num_sect,
+                           int max_size, int usrmem, struct sk_buff** buf)
+{
+       int dsz, sz, hsz, pos, res, cnt;
+
+       dsz = msg_calc_data_size(msg_sect, num_sect);
+       if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
+               *buf = NULL;
+               return -EINVAL;
+       }
+
+       pos = hsz = msg_hdr_sz(hdr);
+       sz = hsz + dsz;
+       msg_set_size(hdr, sz);
+       if (unlikely(sz > max_size)) {
+               *buf = NULL;
+               return dsz;
+       }
+
+       *buf = buf_acquire(sz);
+       if (!(*buf))
+               return -ENOMEM;
+       memcpy((*buf)->data, (unchar *)hdr, hsz);
+       for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
+               if (likely(usrmem))
+                       res = !copy_from_user((*buf)->data + pos, 
+                                             msg_sect[cnt].iov_base, 
+                                             msg_sect[cnt].iov_len);
+               else
+                       memcpy((*buf)->data + pos, msg_sect[cnt].iov_base, 
+                              msg_sect[cnt].iov_len);
+               pos += msg_sect[cnt].iov_len;
+       }
+       if (likely(res))
+               return dsz;
+
+       buf_discard(*buf);
+       *buf = NULL;
+       return -EFAULT;
+}
+
+
+struct tipc_media_addr;
+
+extern void msg_set_media_addr(struct tipc_msg *m,
+                              struct tipc_media_addr *a);
+
+extern void msg_get_media_addr(struct tipc_msg *m,
+                              struct tipc_media_addr *a);
+
+
+#endif
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
new file mode 100644 (file)
index 0000000..41cbaf1
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * net/tipc/name_distr.c: TIPC name distribution code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "cluster.h"
+#include "dbg.h"
+#include "link.h"
+#include "msg.h"
+#include "name_distr.h"
+
+#undef  DBG_OUTPUT
+#define DBG_OUTPUT NULL
+
+#define ITEM_SIZE sizeof(struct distr_item)
+
+/**
+ * struct distr_item - publication info distributed to other nodes
+ * @type: name sequence type
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @ref: publishing port reference
+ * @key: publication key
+ * 
+ * ===> All fields are stored in network byte order. <===
+ * 
+ * First 3 fields identify (name or) name sequence being published.
+ * Reference field uniquely identifies port that published name sequence.
+ * Key field uniquely identifies publication, in the event a port has
+ * multiple publications of the same name sequence.
+ * 
+ * Note: There is no field that identifies the publishing node because it is 
+ * the same for all items contained within a publication message.
+ */
+
+struct distr_item {
+       u32 type;
+       u32 lower;
+       u32 upper;
+       u32 ref;
+       u32 key;
+};
+
+/**
+ * List of externally visible publications by this node -- 
+ * that is, all publications having scope > TIPC_NODE_SCOPE.
+ */
+
+static LIST_HEAD(publ_root);
+static u32 publ_cnt = 0;               
+
+/**
+ * publ_to_item - add publication info to a publication message
+ */
+
+static void publ_to_item(struct distr_item *i, struct publication *p)
+{
+       i->type = htonl(p->type);
+       i->lower = htonl(p->lower);
+       i->upper = htonl(p->upper);
+       i->ref = htonl(p->ref);
+       i->key = htonl(p->key);
+       dbg("publ_to_item: %u, %u, %u\n", p->type, p->lower, p->upper);
+}
+
+/**
+ * named_prepare_buf - allocate & initialize a publication message
+ */
+
+static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
+{
+       struct sk_buff *buf = buf_acquire(LONG_H_SIZE + size);  
+       struct tipc_msg *msg;
+
+       if (buf != NULL) {
+               msg = buf_msg(buf);
+               msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK, 
+                        LONG_H_SIZE, dest);
+               msg_set_size(msg, LONG_H_SIZE + size);
+       }
+       return buf;
+}
+
+/**
+ * named_publish - tell other nodes about a new publication by this node
+ */
+
+void named_publish(struct publication *publ)
+{
+       struct sk_buff *buf;
+       struct distr_item *item;
+
+       list_add(&publ->local_list, &publ_root);
+       publ_cnt++;
+
+       buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
+       if (!buf) {
+               warn("Memory squeeze; failed to distribute publication\n");
+               return;
+       }
+
+       item = (struct distr_item *)msg_data(buf_msg(buf));
+       publ_to_item(item, publ);
+       dbg("named_withdraw: broadcasting publish msg\n");
+       cluster_broadcast(buf);
+}
+
+/**
+ * named_withdraw - tell other nodes about a withdrawn publication by this node
+ */
+
+void named_withdraw(struct publication *publ)
+{
+       struct sk_buff *buf;
+       struct distr_item *item;
+
+       list_del(&publ->local_list);
+       publ_cnt--;
+
+       buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
+       if (!buf) {
+               warn("Memory squeeze; failed to distribute withdrawal\n");
+               return;
+       }
+
+       item = (struct distr_item *)msg_data(buf_msg(buf));
+       publ_to_item(item, publ);
+       dbg("named_withdraw: broadcasting withdraw msg\n");
+       cluster_broadcast(buf);
+}
+
+/**
+ * named_node_up - tell specified node about all publications by this node
+ */
+
+void named_node_up(unsigned long node)
+{
+       struct publication *publ;
+       struct distr_item *item = 0;
+       struct sk_buff *buf = 0;
+       u32 left = 0;
+       u32 rest;
+       u32 max_item_buf;
+
+       assert(in_own_cluster(node));
+       read_lock_bh(&nametbl_lock); 
+       max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
+       max_item_buf *= ITEM_SIZE;
+       rest = publ_cnt * ITEM_SIZE;
+
+       list_for_each_entry(publ, &publ_root, local_list) {
+               if (!buf) {
+                       left = (rest <= max_item_buf) ? rest : max_item_buf;
+                       rest -= left;
+                       buf = named_prepare_buf(PUBLICATION, left, node);       
+                       if (buf == NULL) {
+                               warn("Memory Squeeze; could not send publication\n");
+                               goto exit;
+                       }
+                       item = (struct distr_item *)msg_data(buf_msg(buf));
+               }
+               publ_to_item(item, publ);
+               item++;
+               left -= ITEM_SIZE;
+               if (!left) {
+                       msg_set_link_selector(buf_msg(buf), node);
+                       dbg("named_node_up: sending publish msg to "
+                           "<%u.%u.%u>\n", tipc_zone(node), 
+                           tipc_cluster(node), tipc_node(node));
+                       link_send(buf, node, node);
+                       buf = 0;
+               }
+       }
+exit:
+       read_unlock_bh(&nametbl_lock); 
+}
+
+/**
+ * node_is_down - remove publication associated with a failed node
+ * 
+ * Invoked for each publication issued by a newly failed node.  
+ * Removes publication structure from name table & deletes it.
+ * In rare cases the link may have come back up again when this
+ * function is called, and we have two items representing the same
+ * publication. Nudge this item's key to distinguish it from the other.
+ * (Note: Publication's node subscription is already unsubscribed.)
+ */
+
+static void node_is_down(struct publication *publ)
+{
+       struct publication *p;
+        write_lock_bh(&nametbl_lock);
+       dbg("node_is_down: withdrawing %u, %u, %u\n", 
+           publ->type, publ->lower, publ->upper);
+        publ->key += 1222345;
+       p = nametbl_remove_publ(publ->type, publ->lower, 
+                               publ->node, publ->ref, publ->key);
+        assert(p == publ);
+       write_unlock_bh(&nametbl_lock);
+       if (publ)
+               kfree(publ);
+}
+
+/**
+ * named_recv - process name table update message sent by another node
+ */
+
+void named_recv(struct sk_buff *buf)
+{
+       struct publication *publ;
+       struct tipc_msg *msg = buf_msg(buf);
+       struct distr_item *item = (struct distr_item *)msg_data(msg);
+       u32 count = msg_data_sz(msg) / ITEM_SIZE;
+
+       write_lock_bh(&nametbl_lock); 
+       while (count--) {
+               if (msg_type(msg) == PUBLICATION) {
+                       dbg("named_recv: got publication for %u, %u, %u\n", 
+                           ntohl(item->type), ntohl(item->lower),
+                           ntohl(item->upper));
+                       publ = nametbl_insert_publ(ntohl(item->type), 
+                                                  ntohl(item->lower),
+                                                  ntohl(item->upper),
+                                                  TIPC_CLUSTER_SCOPE,
+                                                  msg_orignode(msg), 
+                                                  ntohl(item->ref),
+                                                  ntohl(item->key));
+                       if (publ) {
+                               nodesub_subscribe(&publ->subscr, 
+                                                 msg_orignode(msg), 
+                                                 publ,
+                                                 (net_ev_handler)node_is_down);
+                       }
+               } else if (msg_type(msg) == WITHDRAWAL) {
+                       dbg("named_recv: got withdrawl for %u, %u, %u\n", 
+                           ntohl(item->type), ntohl(item->lower),
+                           ntohl(item->upper));
+                       publ = nametbl_remove_publ(ntohl(item->type),
+                                                  ntohl(item->lower),
+                                                  msg_orignode(msg),
+                                                  ntohl(item->ref),
+                                                  ntohl(item->key));
+
+                       if (publ) {
+                               nodesub_unsubscribe(&publ->subscr);
+                               kfree(publ);
+                       }
+               } else {
+                       warn("named_recv: unknown msg\n");
+               }
+               item++;
+       }
+       write_unlock_bh(&nametbl_lock); 
+       buf_discard(buf);
+}
+
+/**
+ * named_reinit - re-initialize local publication list
+ * 
+ * This routine is called whenever TIPC networking is (re)enabled.
+ * All existing publications by this node that have "cluster" or "zone" scope
+ * are updated to reflect the node's current network address.
+ * (If the node's address is unchanged, the update loop terminates immediately.)
+ */
+
+void named_reinit(void)
+{
+       struct publication *publ;
+
+       write_lock_bh(&nametbl_lock); 
+       list_for_each_entry(publ, &publ_root, local_list) {
+               if (publ->node == tipc_own_addr)
+                       break;
+               publ->node = tipc_own_addr;
+       }
+       write_unlock_bh(&nametbl_lock); 
+}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
new file mode 100644 (file)
index 0000000..a04bdea
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * net/tipc/name_distr.h: Include file for TIPC name distribution code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NAME_DISTR_H
+#define _TIPC_NAME_DISTR_H
+
+#include "name_table.h"
+
+void named_publish(struct publication *publ);
+void named_withdraw(struct publication *publ);
+void named_node_up(unsigned long node);
+void named_recv(struct sk_buff *buf);
+void named_reinit(void);
+
+#endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
new file mode 100644 (file)
index 0000000..972c83e
--- /dev/null
@@ -0,0 +1,1079 @@
+/*
+ * net/tipc/name_table.c: TIPC name table code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+#include "name_table.h"
+#include "name_distr.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "subscr.h"
+#include "port.h"
+#include "cluster.h"
+#include "bcast.h"
+
+int tipc_nametbl_size = 1024;          /* must be a power of 2 */
+
+/**
+ * struct sub_seq - container for all published instances of a name sequence
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @node_list: circular list of matching publications with >= node scope
+ * @cluster_list: circular list of matching publications with >= cluster scope
+ * @zone_list: circular list of matching publications with >= zone scope
+ */
+
+struct sub_seq {
+       u32 lower;
+       u32 upper;
+       struct publication *node_list;
+       struct publication *cluster_list;
+       struct publication *zone_list;
+};
+
+/** 
+ * struct name_seq - container for all published instances of a name type
+ * @type: 32 bit 'type' value for name sequence
+ * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
+ *        sub-sequences are sorted in ascending order
+ * @alloc: number of sub-sequences currently in array
+ * @first_free: upper bound of highest sub-sequence + 1
+ * @ns_list: links to adjacent name sequences in hash chain
+ * @subscriptions: list of subscriptions for this 'type'
+ * @lock: spinlock controlling access to name sequence structure
+ */
+
+struct name_seq {
+       u32 type;
+       struct sub_seq *sseqs;
+       u32 alloc;
+       u32 first_free;
+       struct hlist_node ns_list;
+       struct list_head subscriptions;
+       spinlock_t lock;
+};
+
+/**
+ * struct name_table - table containing all existing port name publications
+ * @types: pointer to fixed-sized array of name sequence lists, 
+ *         accessed via hashing on 'type'; name sequence lists are *not* sorted
+ * @local_publ_count: number of publications issued by this node
+ */
+
+struct name_table {
+       struct hlist_head *types;
+       u32 local_publ_count;
+};
+
+struct name_table table = { NULL } ;
+static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
+rwlock_t nametbl_lock = RW_LOCK_UNLOCKED;
+
+
+static inline int hash(int x)
+{
+       return(x & (tipc_nametbl_size - 1));
+}
+
+/**
+ * publ_create - create a publication structure
+ */
+
+static struct publication *publ_create(u32 type, u32 lower, u32 upper, 
+                                      u32 scope, u32 node, u32 port_ref,   
+                                      u32 key)
+{
+       struct publication *publ =
+               (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
+       if (publ == NULL) {
+               warn("Memory squeeze; failed to create publication\n");
+               return 0;
+       }
+
+       memset(publ, 0, sizeof(*publ));
+       publ->type = type;
+       publ->lower = lower;
+       publ->upper = upper;
+       publ->scope = scope;
+       publ->node = node;
+       publ->ref = port_ref;
+       publ->key = key;
+       INIT_LIST_HEAD(&publ->local_list);
+       INIT_LIST_HEAD(&publ->pport_list);
+       INIT_LIST_HEAD(&publ->subscr.nodesub_list);
+       return publ;
+}
+
+/**
+ * subseq_alloc - allocate a specified number of sub-sequence structures
+ */
+
+struct sub_seq *subseq_alloc(u32 cnt)
+{
+       u32 sz = cnt * sizeof(struct sub_seq);
+       struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC);
+
+       if (sseq)
+               memset(sseq, 0, sz);
+       return sseq;
+}
+
+/**
+ * nameseq_create - create a name sequence structure for the specified 'type'
+ * 
+ * Allocates a single sub-sequence structure and sets it to all 0's.
+ */
+
+struct name_seq *nameseq_create(u32 type, struct hlist_head *seq_head)
+{
+       struct name_seq *nseq = 
+               (struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC);
+       struct sub_seq *sseq = subseq_alloc(1);
+
+       if (!nseq || !sseq) {
+               warn("Memory squeeze; failed to create name sequence\n");
+               kfree(nseq);
+               kfree(sseq);
+               return 0;
+       }
+
+       memset(nseq, 0, sizeof(*nseq));
+       nseq->lock = SPIN_LOCK_UNLOCKED;
+       nseq->type = type;
+       nseq->sseqs = sseq;
+       dbg("nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n",
+           nseq, type, nseq->sseqs, nseq->first_free);
+       nseq->alloc = 1;
+       INIT_HLIST_NODE(&nseq->ns_list);
+       INIT_LIST_HEAD(&nseq->subscriptions);
+       hlist_add_head(&nseq->ns_list, seq_head);
+       return nseq;
+}
+
+/**
+ * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
+ *  
+ * Very time-critical, so binary searches through sub-sequence array.
+ */
+
+static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq, 
+                                                 u32 instance)
+{
+       struct sub_seq *sseqs = nseq->sseqs;
+       int low = 0;
+       int high = nseq->first_free - 1;
+       int mid;
+
+       while (low <= high) {
+               mid = (low + high) / 2;
+               if (instance < sseqs[mid].lower)
+                       high = mid - 1;
+               else if (instance > sseqs[mid].upper)
+                       low = mid + 1;
+               else
+                       return &sseqs[mid];
+       }
+       return 0;
+}
+
+/**
+ * nameseq_locate_subseq - determine position of name instance in sub-sequence
+ * 
+ * Returns index in sub-sequence array of the entry that contains the specified
+ * instance value; if no entry contains that value, returns the position
+ * where a new entry for it would be inserted in the array.
+ *
+ * Note: Similar to binary search code for locating a sub-sequence.
+ */
+
+static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
+{
+       struct sub_seq *sseqs = nseq->sseqs;
+       int low = 0;
+       int high = nseq->first_free - 1;
+       int mid;
+
+       while (low <= high) {
+               mid = (low + high) / 2;
+               if (instance < sseqs[mid].lower)
+                       high = mid - 1;
+               else if (instance > sseqs[mid].upper)
+                       low = mid + 1;
+               else
+                       return mid;
+       }
+       return low;
+}
+
+/**
+ * nameseq_insert_publ - 
+ */
+
+struct publication *nameseq_insert_publ(struct name_seq *nseq,
+                                       u32 type, u32 lower, u32 upper,
+                                       u32 scope, u32 node, u32 port, u32 key)
+{
+       struct subscription *s;
+       struct subscription *st;
+       struct publication *publ;
+       struct sub_seq *sseq;
+       int created_subseq = 0;
+
+       assert(nseq->first_free <= nseq->alloc);
+       sseq = nameseq_find_subseq(nseq, lower);
+       dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n",
+           nseq, type, lower, sseq);
+       if (sseq) {
+
+               /* Lower end overlaps existing entry => need an exact match */
+
+               if ((sseq->lower != lower) || (sseq->upper != upper)) {
+                       warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
+                       return 0;
+               }
+       } else {
+               u32 inspos;
+               struct sub_seq *freesseq;
+
+               /* Find where lower end should be inserted */
+
+               inspos = nameseq_locate_subseq(nseq, lower);
+
+               /* Fail if upper end overlaps into an existing entry */
+
+               if ((inspos < nseq->first_free) &&
+                   (upper >= nseq->sseqs[inspos].lower)) {
+                       warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
+                       return 0;
+               }
+
+               /* Ensure there is space for new sub-sequence */
+
+               if (nseq->first_free == nseq->alloc) {
+                       struct sub_seq *sseqs = nseq->sseqs;
+                       nseq->sseqs = subseq_alloc(nseq->alloc * 2);
+                       if (nseq->sseqs != NULL) {
+                               memcpy(nseq->sseqs, sseqs,
+                                      nseq->alloc * sizeof (struct sub_seq));
+                               kfree(sseqs);
+                               dbg("Allocated %u sseqs\n", nseq->alloc);
+                               nseq->alloc *= 2;
+                       } else {
+                               warn("Memory squeeze; failed to create sub-sequence\n");
+                               return 0;
+                       }
+               }
+               dbg("Have %u sseqs for type %u\n", nseq->alloc, type);
+
+               /* Insert new sub-sequence */
+
+               dbg("ins in pos %u, ff = %u\n", inspos, nseq->first_free);
+               sseq = &nseq->sseqs[inspos];
+               freesseq = &nseq->sseqs[nseq->first_free];
+               memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof (*sseq));
+               memset(sseq, 0, sizeof (*sseq));
+               nseq->first_free++;
+               sseq->lower = lower;
+               sseq->upper = upper;
+               created_subseq = 1;
+       }
+       dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n",
+           type, lower, upper, node, port, sseq,
+           sseq->lower, sseq->upper, nseq);
+
+       /* Insert a publication: */
+
+       publ = publ_create(type, lower, upper, scope, node, port, key);
+       if (!publ)
+               return 0;
+       dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n",
+           publ, node, publ->node, publ->subscr.node);
+
+       if (!sseq->zone_list)
+               sseq->zone_list = publ->zone_list_next = publ;
+       else {
+               publ->zone_list_next = sseq->zone_list->zone_list_next;
+               sseq->zone_list->zone_list_next = publ;
+       }
+
+       if (in_own_cluster(node)) {
+               if (!sseq->cluster_list)
+                       sseq->cluster_list = publ->cluster_list_next = publ;
+               else {
+                       publ->cluster_list_next =
+                       sseq->cluster_list->cluster_list_next;
+                       sseq->cluster_list->cluster_list_next = publ;
+               }
+       }
+
+       if (node == tipc_own_addr) {
+               if (!sseq->node_list)
+                       sseq->node_list = publ->node_list_next = publ;
+               else {
+                       publ->node_list_next = sseq->node_list->node_list_next;
+                       sseq->node_list->node_list_next = publ;
+               }
+       }
+
+       /* 
+        * Any subscriptions waiting for notification? 
+        */
+       list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
+               dbg("calling report_overlap()\n");
+               subscr_report_overlap(s,
+                                     publ->lower,
+                                     publ->upper,
+                                     TIPC_PUBLISHED,
+                                     publ->ref, 
+                                     publ->node,
+                                     created_subseq);
+       }
+       return publ;
+}
+
+/**
+ * nameseq_remove_publ -
+ */
+
+struct publication *nameseq_remove_publ(struct name_seq *nseq, u32 inst,
+                                       u32 node, u32 ref, u32 key)
+{
+       struct publication *publ;
+       struct publication *prev;
+       struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
+       struct sub_seq *free;
+       struct subscription *s, *st;
+       int removed_subseq = 0;
+
+       assert(nseq);
+
+       if (!sseq) {
+               int i;
+
+               warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst);
+               assert(nseq->sseqs);
+               dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n",
+                   nseq->sseqs, nseq, nseq->alloc, 
+                   nseq->first_free);
+               for (i = 0; i < nseq->first_free; i++) {
+                       dbg("Subseq %u(%x): lower = %u,upper = %u\n",
+                           i, &nseq->sseqs[i], nseq->sseqs[i].lower,
+                           nseq->sseqs[i].upper);
+               }
+               return 0;
+       }
+       dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n",
+           nseq, sseq, nseq->type, inst, key);
+
+       prev = sseq->zone_list;
+       publ = sseq->zone_list->zone_list_next;
+       while ((publ->key != key) || (publ->ref != ref) || 
+              (publ->node && (publ->node != node))) {
+               prev = publ;
+               publ = publ->zone_list_next;
+               assert(prev != sseq->zone_list);
+       }
+       if (publ != sseq->zone_list)
+               prev->zone_list_next = publ->zone_list_next;
+       else if (publ->zone_list_next != publ) {
+               prev->zone_list_next = publ->zone_list_next;
+               sseq->zone_list = publ->zone_list_next;
+       } else {
+               sseq->zone_list = 0;
+       }
+
+       if (in_own_cluster(node)) {
+               prev = sseq->cluster_list;
+               publ = sseq->cluster_list->cluster_list_next;
+               while ((publ->key != key) || (publ->ref != ref) || 
+                      (publ->node && (publ->node != node))) {
+                       prev = publ;
+                       publ = publ->cluster_list_next;
+                       assert(prev != sseq->cluster_list);
+               }
+               if (publ != sseq->cluster_list)
+                       prev->cluster_list_next = publ->cluster_list_next;
+               else if (publ->cluster_list_next != publ) {
+                       prev->cluster_list_next = publ->cluster_list_next;
+                       sseq->cluster_list = publ->cluster_list_next;
+               } else {
+                       sseq->cluster_list = 0;
+               }
+       }
+
+       if (node == tipc_own_addr) {
+               prev = sseq->node_list;
+               publ = sseq->node_list->node_list_next;
+               while ((publ->key != key) || (publ->ref != ref) || 
+                      (publ->node && (publ->node != node))) {
+                       prev = publ;
+                       publ = publ->node_list_next;
+                       assert(prev != sseq->node_list);
+               }
+               if (publ != sseq->node_list)
+                       prev->node_list_next = publ->node_list_next;
+               else if (publ->node_list_next != publ) {
+                       prev->node_list_next = publ->node_list_next;
+                       sseq->node_list = publ->node_list_next;
+               } else {
+                       sseq->node_list = 0;
+               }
+       }
+       assert(!publ->node || (publ->node == node));
+       assert(publ->ref == ref);
+       assert(publ->key == key);
+
+       /* 
+        * Contract subseq list if no more publications:
+        */
+       if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) {
+               free = &nseq->sseqs[nseq->first_free--];
+               memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq));
+               removed_subseq = 1;
+       }
+
+       /* 
+        * Any subscriptions waiting ? 
+        */
+       list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
+               subscr_report_overlap(s,
+                                     publ->lower,
+                                     publ->upper,
+                                     TIPC_WITHDRAWN, 
+                                     publ->ref, 
+                                     publ->node,
+                                     removed_subseq);
+       }
+       return publ;
+}
+
+/**
+ * nameseq_subscribe: attach a subscription, and issue
+ * the prescribed number of events if there is any sub-
+ * sequence overlapping with the requested sequence
+ */
+
+void nameseq_subscribe(struct name_seq *nseq, struct subscription *s)
+{
+       struct sub_seq *sseq = nseq->sseqs;
+
+       list_add(&s->nameseq_list, &nseq->subscriptions);
+
+       if (!sseq)
+               return;
+
+       while (sseq != &nseq->sseqs[nseq->first_free]) {
+               struct publication *zl = sseq->zone_list;
+               if (zl && subscr_overlap(s,sseq->lower,sseq->upper)) {
+                       struct publication *crs = zl;
+                       int must_report = 1;
+
+                       do {
+                               subscr_report_overlap(s, 
+                                                      sseq->lower, 
+                                                      sseq->upper,
+                                                      TIPC_PUBLISHED,
+                                                      crs->ref,
+                                                      crs->node,
+                                                      must_report);
+                               must_report = 0;
+                               crs = crs->zone_list_next;
+                       } while (crs != zl);
+               }
+               sseq++;
+       }
+}
+
+static struct name_seq *nametbl_find_seq(u32 type)
+{
+       struct hlist_head *seq_head;
+       struct hlist_node *seq_node;
+       struct name_seq *ns;
+
+       dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n",
+           type, ntohl(type), type, table.types, hash(type));
+
+       seq_head = &table.types[hash(type)];
+       hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
+               if (ns->type == type) {
+                       dbg("found %x\n", ns);
+                       return ns;
+               }
+       }
+
+       return 0;
+};
+
+struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper,
+                   u32 scope, u32 node, u32 port, u32 key)
+{
+       struct name_seq *seq = nametbl_find_seq(type);
+
+       dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq);
+       if (lower > upper) {
+               warn("Failed to publish illegal <%u,%u,%u>\n",
+                    type, lower, upper);
+               return 0;
+       }
+
+       dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node);
+       if (!seq) {
+               seq = nameseq_create(type, &table.types[hash(type)]);
+               dbg("nametbl_insert_publ: created %x\n", seq);
+       }
+       if (!seq)
+               return 0;
+
+       assert(seq->type == type);
+       return nameseq_insert_publ(seq, type, lower, upper,
+                                  scope, node, port, key);
+}
+
+struct publication *nametbl_remove_publ(u32 type, u32 lower, 
+                                       u32 node, u32 ref, u32 key)
+{
+       struct publication *publ;
+       struct name_seq *seq = nametbl_find_seq(type);
+
+       if (!seq)
+               return 0;
+
+       dbg("Withdrawing <%u,%u> from %x\n", type, lower, node);
+       publ = nameseq_remove_publ(seq, lower, node, ref, key);
+
+       if (!seq->first_free && list_empty(&seq->subscriptions)) {
+               hlist_del_init(&seq->ns_list);
+               kfree(seq->sseqs);
+               kfree(seq);
+       }
+       return publ;
+}
+
+/*
+ * nametbl_translate(): Translate tipc_name -> tipc_portid.
+ *                      Very time-critical.
+ *
+ * Note: on entry 'destnode' is the search domain used during translation;
+ *       on exit it passes back the node address of the matching port (if any)
+ */
+
+u32 nametbl_translate(u32 type, u32 instance, u32 *destnode)
+{
+       struct sub_seq *sseq;
+       struct publication *publ = 0;
+       struct name_seq *seq;
+       u32 ref;
+
+       if (!in_scope(*destnode, tipc_own_addr))
+               return 0;
+
+       read_lock_bh(&nametbl_lock);
+       seq = nametbl_find_seq(type);
+       if (unlikely(!seq))
+               goto not_found;
+       sseq = nameseq_find_subseq(seq, instance);
+       if (unlikely(!sseq))
+               goto not_found;
+       spin_lock_bh(&seq->lock);
+
+       /* Closest-First Algorithm: */
+       if (likely(!*destnode)) {
+               publ = sseq->node_list;
+               if (publ) {
+                       sseq->node_list = publ->node_list_next;
+found:
+                       ref = publ->ref;
+                       *destnode = publ->node;
+                       spin_unlock_bh(&seq->lock);
+                       read_unlock_bh(&nametbl_lock);
+                       return ref;
+               }
+               publ = sseq->cluster_list;
+               if (publ) {
+                       sseq->cluster_list = publ->cluster_list_next;
+                       goto found;
+               }
+               publ = sseq->zone_list;
+               if (publ) {
+                       sseq->zone_list = publ->zone_list_next;
+                       goto found;
+               }
+       }
+
+       /* Round-Robin Algorithm: */
+       else if (*destnode == tipc_own_addr) {
+               publ = sseq->node_list;
+               if (publ) {
+                       sseq->node_list = publ->node_list_next;
+                       goto found;
+               }
+       } else if (in_own_cluster(*destnode)) {
+               publ = sseq->cluster_list;
+               if (publ) {
+                       sseq->cluster_list = publ->cluster_list_next;
+                       goto found;
+               }
+       } else {
+               publ = sseq->zone_list;
+               if (publ) {
+                       sseq->zone_list = publ->zone_list_next;
+                       goto found;
+               }
+       }
+       spin_unlock_bh(&seq->lock);
+not_found:
+       *destnode = 0;
+       read_unlock_bh(&nametbl_lock);
+       return 0;
+}
+
+/**
+ * nametbl_mc_translate - find multicast destinations
+ * 
+ * Creates list of all local ports that overlap the given multicast address;
+ * also determines if any off-node ports overlap.
+ *
+ * Note: Publications with a scope narrower than 'limit' are ignored.
+ * (i.e. local node-scope publications mustn't receive messages arriving
+ * from another node, even if the multcast link brought it here)
+ * 
+ * Returns non-zero if any off-node ports overlap
+ */
+
+int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
+                        struct port_list *dports)
+{
+       struct name_seq *seq;
+       struct sub_seq *sseq;
+       struct sub_seq *sseq_stop;
+       int res = 0;
+
+       read_lock_bh(&nametbl_lock);
+       seq = nametbl_find_seq(type);
+       if (!seq)
+               goto exit;
+
+       spin_lock_bh(&seq->lock);
+
+       sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
+       sseq_stop = seq->sseqs + seq->first_free;
+       for (; sseq != sseq_stop; sseq++) {
+               struct publication *publ;
+
+               if (sseq->lower > upper)
+                       break;
+               publ = sseq->cluster_list;
+               if (publ && (publ->scope <= limit))
+                       do {
+                               if (publ->node == tipc_own_addr)
+                                       port_list_add(dports, publ->ref);
+                               else
+                                       res = 1;
+                               publ = publ->cluster_list_next;
+                       } while (publ != sseq->cluster_list);
+       }
+
+       spin_unlock_bh(&seq->lock);
+exit:
+       read_unlock_bh(&nametbl_lock);
+       return res;
+}
+
+/**
+ * nametbl_publish_rsv - publish port name using a reserved name type
+ */
+
+int nametbl_publish_rsv(u32 ref, unsigned int scope, 
+                       struct tipc_name_seq const *seq)
+{
+       int res;
+
+       atomic_inc(&rsv_publ_ok);
+       res = tipc_publish(ref, scope, seq);
+       atomic_dec(&rsv_publ_ok);
+       return res;
+}
+
+/**
+ * nametbl_publish - add name publication to network name tables
+ */
+
+struct publication *nametbl_publish(u32 type, u32 lower, u32 upper, 
+                                   u32 scope, u32 port_ref, u32 key)
+{
+       struct publication *publ;
+
+       if (table.local_publ_count >= tipc_max_publications) {
+               warn("Failed publish: max %u local publication\n", 
+                    tipc_max_publications);
+               return 0;
+       }
+       if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
+               warn("Failed to publish reserved name <%u,%u,%u>\n",
+                    type, lower, upper);
+               return 0;
+       }
+
+       write_lock_bh(&nametbl_lock);
+       table.local_publ_count++;
+       publ = nametbl_insert_publ(type, lower, upper, scope,
+                                  tipc_own_addr, port_ref, key);
+       if (publ && (scope != TIPC_NODE_SCOPE)) {
+               named_publish(publ);
+       }
+       write_unlock_bh(&nametbl_lock);
+       return publ;
+}
+
+/**
+ * nametbl_withdraw - withdraw name publication from network name tables
+ */
+
+int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
+{
+       struct publication *publ;
+
+       dbg("nametbl_withdraw:<%d,%d,%d>\n", type, lower, key);
+       write_lock_bh(&nametbl_lock);
+       publ = nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
+       if (publ) {
+               table.local_publ_count--;
+               if (publ->scope != TIPC_NODE_SCOPE)
+                       named_withdraw(publ);
+               write_unlock_bh(&nametbl_lock);
+               list_del_init(&publ->pport_list);
+               kfree(publ);
+               return 1;
+       }
+       write_unlock_bh(&nametbl_lock);
+       return 0;
+}
+
+/**
+ * nametbl_subscribe - add a subscription object to the name table
+ */
+
+void
+nametbl_subscribe(struct subscription *s)
+{
+       u32 type = s->seq.type;
+       struct name_seq *seq;
+
+        write_lock_bh(&nametbl_lock);
+       seq = nametbl_find_seq(type);
+       if (!seq) {
+               seq = nameseq_create(type, &table.types[hash(type)]);
+       }
+        if (seq){
+                spin_lock_bh(&seq->lock);
+                dbg("nametbl_subscribe:found %x for <%u,%u,%u>\n",
+                    seq, type, s->seq.lower, s->seq.upper);
+                assert(seq->type == type);
+                nameseq_subscribe(seq, s);
+                spin_unlock_bh(&seq->lock);
+        }
+        write_unlock_bh(&nametbl_lock);
+}
+
+/**
+ * nametbl_unsubscribe - remove a subscription object from name table
+ */
+
+void
+nametbl_unsubscribe(struct subscription *s)
+{
+       struct name_seq *seq;
+
+        write_lock_bh(&nametbl_lock);
+        seq = nametbl_find_seq(s->seq.type);
+       if (seq != NULL){
+                spin_lock_bh(&seq->lock);
+                list_del_init(&s->nameseq_list);
+                spin_unlock_bh(&seq->lock);
+                if ((seq->first_free == 0) && list_empty(&seq->subscriptions)) {
+                        hlist_del_init(&seq->ns_list);
+                        kfree(seq->sseqs);
+                        kfree(seq);
+                }
+        }
+        write_unlock_bh(&nametbl_lock);
+}
+
+
+/**
+ * subseq_list: print specified sub-sequence contents into the given buffer
+ */
+
+static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
+                       u32 index)
+{
+       char portIdStr[27];
+       char *scopeStr;
+       struct publication *publ = sseq->zone_list;
+
+       tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper);
+
+       if (depth == 2 || !publ) {
+               tipc_printf(buf, "\n");
+               return;
+       }
+
+       do {
+               sprintf (portIdStr, "<%u.%u.%u:%u>",
+                        tipc_zone(publ->node), tipc_cluster(publ->node),
+                        tipc_node(publ->node), publ->ref);
+               tipc_printf(buf, "%-26s ", portIdStr);
+               if (depth > 3) {
+                       if (publ->node != tipc_own_addr)
+                               scopeStr = "";
+                       else if (publ->scope == TIPC_NODE_SCOPE)
+                               scopeStr = "node";
+                       else if (publ->scope == TIPC_CLUSTER_SCOPE)
+                               scopeStr = "cluster";
+                       else
+                               scopeStr = "zone";
+                       tipc_printf(buf, "%-10u %s", publ->key, scopeStr);
+               }
+
+               publ = publ->zone_list_next;
+               if (publ == sseq->zone_list)
+                       break;
+
+               tipc_printf(buf, "\n%33s", " ");
+       } while (1);
+
+       tipc_printf(buf, "\n");
+}
+
+/**
+ * nameseq_list: print specified name sequence contents into the given buffer
+ */
+
+static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
+                        u32 type, u32 lowbound, u32 upbound, u32 index)
+{
+       struct sub_seq *sseq;
+       char typearea[11];
+
+       sprintf(typearea, "%-10u", seq->type);
+
+       if (depth == 1) {
+               tipc_printf(buf, "%s\n", typearea);
+               return;
+       }
+
+       for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
+               if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
+                       tipc_printf(buf, "%s ", typearea);
+                       subseq_list(sseq, buf, depth, index);
+                       sprintf(typearea, "%10s", " ");
+               }
+       }
+}
+
+/**
+ * nametbl_header - print name table header into the given buffer
+ */
+
+static void nametbl_header(struct print_buf *buf, u32 depth)
+{
+       tipc_printf(buf, "Type       ");
+
+       if (depth > 1)
+               tipc_printf(buf, "Lower      Upper      ");
+       if (depth > 2)
+               tipc_printf(buf, "Port Identity              ");
+       if (depth > 3)
+               tipc_printf(buf, "Publication");
+
+       tipc_printf(buf, "\n-----------");
+
+       if (depth > 1)
+               tipc_printf(buf, "--------------------- ");
+       if (depth > 2)
+               tipc_printf(buf, "-------------------------- ");
+       if (depth > 3)
+               tipc_printf(buf, "------------------");
+
+       tipc_printf(buf, "\n");
+}
+
+/**
+ * nametbl_list - print specified name table contents into the given buffer
+ */
+
+static void nametbl_list(struct print_buf *buf, u32 depth_info, 
+                        u32 type, u32 lowbound, u32 upbound)
+{
+       struct hlist_head *seq_head;
+       struct hlist_node *seq_node;
+       struct name_seq *seq;
+       int all_types;
+       u32 depth;
+       u32 i;
+
+       all_types = (depth_info & TIPC_NTQ_ALLTYPES);
+       depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
+
+       if (depth == 0)
+               return;
+
+       if (all_types) {
+               /* display all entries in name table to specified depth */
+               nametbl_header(buf, depth);
+               lowbound = 0;
+               upbound = ~0;
+               for (i = 0; i < tipc_nametbl_size; i++) {
+                       seq_head = &table.types[i];
+                       hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
+                               nameseq_list(seq, buf, depth, seq->type, 
+                                            lowbound, upbound, i);
+                       }
+               }
+       } else {
+               /* display only the sequence that matches the specified type */
+               if (upbound < lowbound) {
+                       tipc_printf(buf, "invalid name sequence specified\n");
+                       return;
+               }
+               nametbl_header(buf, depth);
+               i = hash(type);
+               seq_head = &table.types[i];
+               hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
+                       if (seq->type == type) {
+                               nameseq_list(seq, buf, depth, type, 
+                                            lowbound, upbound, i);
+                               break;
+                       }
+               }
+       }
+}
+
+void nametbl_print(struct print_buf *buf, const char *str)
+{
+       tipc_printf(buf, str);
+       read_lock_bh(&nametbl_lock);
+       nametbl_list(buf, 0, 0, 0, 0);
+       read_unlock_bh(&nametbl_lock);
+}
+
+#define MAX_NAME_TBL_QUERY 32768
+
+struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space)
+{
+       struct sk_buff *buf;
+       struct tipc_name_table_query *argv;
+       struct tlv_desc *rep_tlv;
+       struct print_buf b;
+       int str_len;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       buf = cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY));
+       if (!buf)
+               return NULL;
+
+       rep_tlv = (struct tlv_desc *)buf->data;
+       printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY);
+       argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
+       read_lock_bh(&nametbl_lock);
+       nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type), 
+                    ntohl(argv->lowbound), ntohl(argv->upbound));
+       read_unlock_bh(&nametbl_lock);
+       str_len = printbuf_validate(&b);
+
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
+void nametbl_dump(void)
+{
+       nametbl_list(CONS, 0, 0, 0, 0);
+}
+
+int nametbl_init(void)
+{
+       int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
+
+       table.types = (struct hlist_head *)kmalloc(array_size, GFP_ATOMIC);
+       if (!table.types)
+               return -ENOMEM;
+
+       write_lock_bh(&nametbl_lock);
+       memset(table.types, 0, array_size);
+       table.local_publ_count = 0;
+       write_unlock_bh(&nametbl_lock);
+       return 0;
+}
+
+void nametbl_stop(void)
+{
+       struct hlist_head *seq_head;
+       struct hlist_node *seq_node;
+       struct hlist_node *tmp;
+       struct name_seq *seq;
+       u32 i;
+
+       if (!table.types)
+               return;
+
+       write_lock_bh(&nametbl_lock);
+       for (i = 0; i < tipc_nametbl_size; i++) {
+               seq_head = &table.types[i];
+               hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) {
+                       struct sub_seq *sseq = seq->sseqs;
+
+                       for (; sseq != &seq->sseqs[seq->first_free]; sseq++) {
+                               struct publication *publ = sseq->zone_list;
+                               assert(publ);
+                               do {
+                                       struct publication *next =
+                                               publ->zone_list_next;
+                                       kfree(publ);
+                                       publ = next;
+                               }
+                               while (publ != sseq->zone_list);
+                       }
+               }
+       }
+       kfree(table.types);
+       table.types = NULL;
+       write_unlock_bh(&nametbl_lock);
+}
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
new file mode 100644 (file)
index 0000000..f826933
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * net/tipc/name_table.h: Include file for TIPC name table code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NAME_TABLE_H
+#define _TIPC_NAME_TABLE_H
+
+#include "node_subscr.h"
+
+struct subscription;
+struct port_list;
+
+/*
+ * TIPC name types reserved for internal TIPC use (both current and planned)
+ */
+
+#define TIPC_ZM_SRV 3                  /* zone master service name type */
+
+
+/**
+ * struct publication - info about a published (name or) name sequence
+ * @type: name sequence type
+ * @lower: name sequence lower bound
+ * @upper: name sequence upper bound
+ * @scope: scope of publication
+ * @node: network address of publishing port's node
+ * @ref: publishing port
+ * @key: publication key
+ * @subscr: subscription to "node down" event (for off-node publications only)
+ * @local_list: adjacent entries in list of publications made by this node
+ * @pport_list: adjacent entries in list of publications made by this port
+ * @node_list: next matching name seq publication with >= node scope
+ * @cluster_list: next matching name seq publication with >= cluster scope
+ * @zone_list: next matching name seq publication with >= zone scope
+ * 
+ * Note that the node list, cluster list, and zone list are circular lists.
+ */
+
+struct publication {
+       u32 type;
+       u32 lower;
+       u32 upper;
+       u32 scope;
+       u32 node;
+       u32 ref;
+       u32 key;
+       struct node_subscr subscr;
+       struct list_head local_list;
+       struct list_head pport_list;
+       struct publication *node_list_next;
+       struct publication *cluster_list_next;
+       struct publication *zone_list_next;
+};
+
+
+extern rwlock_t nametbl_lock;
+
+struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space);
+u32 nametbl_translate(u32 type, u32 instance, u32 *node);
+int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, 
+                        struct port_list *dports);
+int nametbl_publish_rsv(u32 ref, unsigned int scope, 
+                       struct tipc_name_seq const *seq);
+struct publication *nametbl_publish(u32 type, u32 lower, u32 upper,
+                                   u32 scope, u32 port_ref, u32 key);
+int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key);
+struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper,
+                                       u32 scope, u32 node, u32 ref, u32 key);
+struct publication *nametbl_remove_publ(u32 type, u32 lower, 
+                                       u32 node, u32 ref, u32 key);
+void nametbl_subscribe(struct subscription *s);
+void nametbl_unsubscribe(struct subscription *s);
+int nametbl_init(void);
+void nametbl_stop(void);
+
+#endif
diff --git a/net/tipc/net.c b/net/tipc/net.c
new file mode 100644 (file)
index 0000000..6826b49
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * net/tipc/net.c: TIPC network routing code
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "bearer.h"
+#include "net.h"
+#include "zone.h"
+#include "addr.h"
+#include "name_table.h"
+#include "name_distr.h"
+#include "subscr.h"
+#include "link.h"
+#include "msg.h"
+#include "port.h"
+#include "bcast.h"
+#include "discover.h"
+#include "config.h"
+
+/* 
+ * The TIPC locking policy is designed to ensure a very fine locking
+ * granularity, permitting complete parallel access to individual
+ * port and node/link instances. The code consists of three major 
+ * locking domains, each protected with their own disjunct set of locks.
+ *
+ * 1: The routing hierarchy.
+ *    Comprises the structures 'zone', 'cluster', 'node', 'link' 
+ *    and 'bearer'. The whole hierarchy is protected by a big 
+ *    read/write lock, net_lock, to enssure that nothing is added 
+ *    or removed while code is accessing any of these structures. 
+ *    This layer must not be called from the two others while they 
+ *    hold any of their own locks.
+ *    Neither must it itself do any upcalls to the other two before
+ *    it has released net_lock and other protective locks.
+ *
+ *   Within the net_lock domain there are two sub-domains;'node' and 
+ *   'bearer', where local write operations are permitted,
+ *   provided that those are protected by individual spin_locks
+ *   per instance. Code holding net_lock(read) and a node spin_lock 
+ *   is permitted to poke around in both the node itself and its
+ *   subordinate links. I.e, it can update link counters and queues, 
+ *   change link state, send protocol messages, and alter the 
+ *   "active_links" array in the node; but it can _not_ remove a link 
+ *   or a node from the overall structure.
+ *   Correspondingly, individual bearers may change status within a 
+ *   net_lock(read), protected by an individual spin_lock ber bearer 
+ *   instance, but it needs net_lock(write) to remove/add any bearers.
+ *     
+ *
+ *  2: The transport level of the protocol. 
+ *     This consists of the structures port, (and its user level 
+ *     representations, such as user_port and tipc_sock), reference and 
+ *     tipc_user (port.c, reg.c, socket.c). 
+ *
+ *     This layer has four different locks:
+ *     - The tipc_port spin_lock. This is protecting each port instance
+ *       from parallel data access and removal. Since we can not place 
+ *       this lock in the port itself, it has been placed in the 
+ *       corresponding reference table entry, which has the same life
+ *       cycle as the module. This entry is difficult to access from 
+ *       outside the TIPC core, however, so a pointer to the lock has 
+ *       been added in the port instance, -to be used for unlocking 
+ *       only.
+ *     - A read/write lock to protect the reference table itself (teg.c). 
+ *       (Nobody is using read-only access to this, so it can just as 
+ *       well be changed to a spin_lock)
+ *     - A spin lock to protect the registry of kernel/driver users (reg.c)
+ *     - A global spin_lock (port_lock), which only task is to ensure 
+ *       consistency where more than one port is involved in an operation,
+ *       i.e., whe a port is part of a linked list of ports.
+ *       There are two such lists; 'port_list', which is used for management,
+ *       and 'wait_list', which is used to queue ports during congestion.
+ *     
+ *  3: The name table (name_table.c, name_distr.c, subscription.c)
+ *     - There is one big read/write-lock (nametbl_lock) protecting the 
+ *       overall name table structure. Nothing must be added/removed to 
+ *       this structure without holding write access to it.
+ *     - There is one local spin_lock per sub_sequence, which can be seen
+ *       as a sub-domain to the nametbl_lock domain. It is used only
+ *       for translation operations, and is needed because a translation
+ *       steps the root of the 'publication' linked list between each lookup.
+ *       This is always used within the scope of a nametbl_lock(read).
+ *     - A local spin_lock protecting the queue of subscriber events.
+*/
+
+rwlock_t net_lock = RW_LOCK_UNLOCKED;
+struct network net = { 0 };
+
+struct node *net_select_remote_node(u32 addr, u32 ref) 
+{
+       return zone_select_remote_node(net.zones[tipc_zone(addr)], addr, ref);
+}
+
+u32 net_select_router(u32 addr, u32 ref)
+{
+       return zone_select_router(net.zones[tipc_zone(addr)], addr, ref);
+}
+
+
+u32 net_next_node(u32 a)
+{
+       if (net.zones[tipc_zone(a)])
+               return zone_next_node(a);
+       return 0;
+}
+
+void net_remove_as_router(u32 router)
+{
+       u32 z_num;
+
+       for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+               if (!net.zones[z_num])
+                       continue;
+               zone_remove_as_router(net.zones[z_num], router);
+       }
+}
+
+void net_send_external_routes(u32 dest)
+{
+       u32 z_num;
+
+       for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+               if (net.zones[z_num])
+                       zone_send_external_routes(net.zones[z_num], dest);
+       }
+}
+
+int net_init(void)
+{
+       u32 sz = sizeof(struct _zone *) * (tipc_max_zones + 1);
+
+       memset(&net, 0, sizeof(net));
+       net.zones = (struct _zone **)kmalloc(sz, GFP_ATOMIC);
+       if (!net.zones) {
+               return -ENOMEM;
+       }
+       memset(net.zones, 0, sz);
+       return TIPC_OK;
+}
+
+void net_stop(void)
+{
+       u32 z_num;
+
+       if (!net.zones)
+               return;
+
+       for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
+               zone_delete(net.zones[z_num]);
+       }
+       kfree(net.zones);
+       net.zones = 0;
+}
+
+static void net_route_named_msg(struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       u32 dnode;
+       u32 dport;
+
+       if (!msg_named(msg)) {
+               msg_dbg(msg, "net->drop_nam:");
+               buf_discard(buf);
+               return;
+       }
+
+       dnode = addr_domain(msg_lookup_scope(msg));
+       dport = nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode);
+       dbg("net->lookup<%u,%u>-><%u,%x>\n",
+           msg_nametype(msg), msg_nameinst(msg), dport, dnode);
+       if (dport) {
+               msg_set_destnode(msg, dnode);
+               msg_set_destport(msg, dport);
+               net_route_msg(buf);
+               return;
+       }
+       msg_dbg(msg, "net->rej:NO NAME: ");
+       tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
+}
+
+void net_route_msg(struct sk_buff *buf)
+{
+       struct tipc_msg *msg;
+       u32 dnode;
+
+       if (!buf)
+               return;
+       msg = buf_msg(buf);
+
+       msg_incr_reroute_cnt(msg);
+       if (msg_reroute_cnt(msg) > 6) {
+               if (msg_errcode(msg)) {
+                       msg_dbg(msg, "NET>DISC>:");
+                       buf_discard(buf);
+               } else {
+                       msg_dbg(msg, "NET>REJ>:");
+                       tipc_reject_msg(buf, msg_destport(msg) ? 
+                                       TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME);
+               }
+               return;
+       }
+
+       msg_dbg(msg, "net->rout: ");
+
+       /* Handle message for this node */
+       dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
+       if (in_scope(dnode, tipc_own_addr)) {
+               if (msg_isdata(msg)) {
+                       if (msg_mcast(msg)) 
+                               port_recv_mcast(buf, NULL);
+                       else if (msg_destport(msg))
+                               port_recv_msg(buf);
+                       else
+                               net_route_named_msg(buf);
+                       return;
+               }
+               switch (msg_user(msg)) {
+               case ROUTE_DISTRIBUTOR:
+                       cluster_recv_routing_table(buf);
+                       break;
+               case NAME_DISTRIBUTOR:
+                       named_recv(buf);
+                       break;
+               case CONN_MANAGER:
+                       port_recv_proto_msg(buf);
+                       break;
+               default:
+                       msg_dbg(msg,"DROP/NET/<REC<");
+                       buf_discard(buf);
+               }
+               return;
+       }
+
+       /* Handle message for another node */
+       msg_dbg(msg, "NET>SEND>: ");
+       link_send(buf, dnode, msg_link_selector(msg));
+}
+
+int tipc_start_net(void)
+{
+       char addr_string[16];
+       int res;
+
+       if (tipc_mode != TIPC_NODE_MODE)
+               return -ENOPROTOOPT;
+
+       tipc_mode = TIPC_NET_MODE;
+       named_reinit();
+       port_reinit();
+
+       if ((res = bearer_init()) ||
+           (res = net_init()) ||
+           (res = cluster_init()) ||
+           (res = bclink_init())) {
+               return res;
+       }
+        subscr_stop();
+       cfg_stop();
+       k_signal((Handler)subscr_start, 0);
+       k_signal((Handler)cfg_init, 0);
+       info("Started in network mode\n");
+       info("Own node address %s, network identity %u\n",
+            addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
+       return TIPC_OK;
+}
+
+void tipc_stop_net(void)
+{
+       if (tipc_mode != TIPC_NET_MODE)
+               return;
+        write_lock_bh(&net_lock);
+       bearer_stop();
+       tipc_mode = TIPC_NODE_MODE;
+       bclink_stop();
+       net_stop();
+        write_unlock_bh(&net_lock);
+       info("Left network mode \n");
+}
+
diff --git a/net/tipc/net.h b/net/tipc/net.h
new file mode 100644 (file)
index 0000000..948c6d4
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * net/tipc/net.h: Include file for TIPC network routing code
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NET_H
+#define _TIPC_NET_H
+
+struct _zone;
+
+/**
+ * struct network - TIPC network structure
+ * @zones: array of pointers to all zones within network
+ */
+struct network {
+       struct _zone **zones;
+};
+
+
+extern struct network net;
+extern rwlock_t net_lock;
+
+int net_init(void);
+void net_stop(void);
+void net_remove_as_router(u32 router);
+void net_send_external_routes(u32 dest);
+void net_route_msg(struct sk_buff *buf);
+struct node *net_select_remote_node(u32 addr, u32 ref);
+u32 net_select_router(u32 addr, u32 ref);
+
+int tipc_start_net(void);
+void tipc_stop_net(void);
+
+#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
new file mode 100644 (file)
index 0000000..19b3f40
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * net/tipc/netlink.c: TIPC configuration handling
+ * 
+ * Copyright (c) 2005-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include <net/genetlink.h>
+
+static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
+{
+       struct sk_buff *rep_buf;
+       struct nlmsghdr *rep_nlh;
+       struct nlmsghdr *req_nlh = info->nlhdr;
+       struct tipc_genlmsghdr *req_userhdr = info->userhdr;
+       int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
+
+       if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
+               rep_buf = cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
+       else
+               rep_buf = cfg_do_cmd(req_userhdr->dest,
+                                    req_userhdr->cmd,
+                                    NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
+                                    NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
+                                    hdr_space);
+
+       if (rep_buf) {
+               skb_push(rep_buf, hdr_space);
+               rep_nlh = (struct nlmsghdr *)rep_buf->data;
+               memcpy(rep_nlh, req_nlh, hdr_space);
+               rep_nlh->nlmsg_len = rep_buf->len;
+               genlmsg_unicast(rep_buf, req_nlh->nlmsg_pid);
+       }
+
+        return 0;
+}
+
+static struct genl_family family = {
+        .id            = GENL_ID_GENERATE,
+        .name          = TIPC_GENL_NAME,
+        .version       = TIPC_GENL_VERSION,
+        .hdrsize       = TIPC_GENL_HDRLEN,
+        .maxattr       = 0,
+};
+
+static struct genl_ops ops = {
+       .cmd            = TIPC_GENL_CMD,
+       .doit           = handle_cmd,
+};
+
+static int family_registered = 0;
+
+int netlink_start(void)
+{
+
+
+       if (genl_register_family(&family))
+               goto err;
+
+       family_registered = 1;
+
+       if (genl_register_ops(&family, &ops))
+               goto err_unregister;
+
+        return 0;
+
+ err_unregister:
+       genl_unregister_family(&family);
+       family_registered = 0;
+ err:
+       err("Failed to register netlink interface\n");
+       return -EFAULT;
+}
+
+void netlink_stop(void)
+{
+       if (family_registered) {
+               genl_unregister_family(&family);
+               family_registered = 0;
+       }
+}
diff --git a/net/tipc/node.c b/net/tipc/node.c
new file mode 100644 (file)
index 0000000..05688d0
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * net/tipc/node.c: TIPC node management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "node.h"
+#include "cluster.h"
+#include "net.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "link.h"
+#include "port.h"
+#include "bearer.h"
+#include "name_distr.h"
+#include "net.h"
+
+void node_print(struct print_buf *buf, struct node *n_ptr, char *str);
+static void node_lost_contact(struct node *n_ptr);
+static void node_established_contact(struct node *n_ptr);
+
+struct node *nodes = NULL;     /* sorted list of nodes within cluster */
+
+u32 tipc_own_tag = 0;
+
+struct node *node_create(u32 addr)
+{
+       struct cluster *c_ptr;
+       struct node *n_ptr;
+        struct node **curr_node;
+
+       n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC);
+        if (n_ptr != NULL) {
+                memset(n_ptr, 0, sizeof(*n_ptr));
+                n_ptr->addr = addr;
+                n_ptr->lock =  SPIN_LOCK_UNLOCKED;     
+                INIT_LIST_HEAD(&n_ptr->nsub);
+       
+               c_ptr = cluster_find(addr);
+                if (c_ptr == NULL)
+                        c_ptr = cluster_create(addr);
+                if (c_ptr != NULL) {
+                        n_ptr->owner = c_ptr;
+                        cluster_attach_node(c_ptr, n_ptr);
+                        n_ptr->last_router = -1;
+
+                        /* Insert node into ordered list */
+                        for (curr_node = &nodes; *curr_node; 
+                            curr_node = &(*curr_node)->next) {
+                                if (addr < (*curr_node)->addr) {
+                                        n_ptr->next = *curr_node;
+                                        break;
+                                }
+                        }
+                        (*curr_node) = n_ptr;
+                } else {
+                        kfree(n_ptr);
+                        n_ptr = NULL;
+                }
+        }
+       return n_ptr;
+}
+
+void node_delete(struct node *n_ptr)
+{
+       if (!n_ptr)
+               return;
+
+#if 0
+       /* Not needed because links are already deleted via bearer_stop() */
+
+       u32 l_num;
+
+       for (l_num = 0; l_num < MAX_BEARERS; l_num++) {
+               link_delete(n_ptr->links[l_num]);
+       }
+#endif
+
+       dbg("node %x deleted\n", n_ptr->addr);
+       kfree(n_ptr);
+}
+
+
+/**
+ * node_link_up - handle addition of link
+ * 
+ * Link becomes active (alone or shared) or standby, depending on its priority.
+ */
+
+void node_link_up(struct node *n_ptr, struct link *l_ptr)
+{
+       struct link **active = &n_ptr->active_links[0];
+
+       info("Established link <%s> on network plane %c\n",
+            l_ptr->name, l_ptr->b_ptr->net_plane);
+       
+       if (!active[0]) {
+               dbg(" link %x into %x/%x\n", l_ptr, &active[0], &active[1]);
+               active[0] = active[1] = l_ptr;
+               node_established_contact(n_ptr);
+               return;
+       }
+       if (l_ptr->priority < active[0]->priority) { 
+               info("Link is standby\n");
+               return;
+       }
+       link_send_duplicate(active[0], l_ptr);
+       if (l_ptr->priority == active[0]->priority) { 
+               active[0] = l_ptr;
+               return;
+       }
+       info("Link <%s> on network plane %c becomes standby\n",
+            active[0]->name, active[0]->b_ptr->net_plane);
+       active[0] = active[1] = l_ptr;
+}
+
+/**
+ * node_select_active_links - select active link
+ */
+
+static void node_select_active_links(struct node *n_ptr)
+{
+       struct link **active = &n_ptr->active_links[0];
+       u32 i;
+       u32 highest_prio = 0;
+
+        active[0] = active[1] = 0;
+
+       for (i = 0; i < MAX_BEARERS; i++) {
+                struct link *l_ptr = n_ptr->links[i];
+
+               if (!l_ptr || !link_is_up(l_ptr) ||
+                   (l_ptr->priority < highest_prio))
+                       continue;
+
+               if (l_ptr->priority > highest_prio) {
+                        highest_prio = l_ptr->priority;
+                       active[0] = active[1] = l_ptr;
+               } else {
+                       active[1] = l_ptr;
+               }
+       }
+}
+
+/**
+ * node_link_down - handle loss of link
+ */
+
+void node_link_down(struct node *n_ptr, struct link *l_ptr)
+{
+       struct link **active;
+
+       if (!link_is_active(l_ptr)) {
+               info("Lost standby link <%s> on network plane %c\n",
+                    l_ptr->name, l_ptr->b_ptr->net_plane);
+               return;
+       }
+       info("Lost link <%s> on network plane %c\n",
+               l_ptr->name, l_ptr->b_ptr->net_plane);
+
+       active = &n_ptr->active_links[0];
+       if (active[0] == l_ptr)
+               active[0] = active[1];
+       if (active[1] == l_ptr)
+               active[1] = active[0];
+       if (active[0] == l_ptr)
+               node_select_active_links(n_ptr);
+       if (node_is_up(n_ptr)) 
+               link_changeover(l_ptr);
+       else 
+               node_lost_contact(n_ptr);
+}
+
+int node_has_active_links(struct node *n_ptr)
+{
+       return (n_ptr && 
+               ((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
+}
+
+int node_has_redundant_links(struct node *n_ptr)
+{
+       return (node_has_active_links(n_ptr) &&
+               (n_ptr->active_links[0] != n_ptr->active_links[1]));
+}
+
+int node_has_active_routes(struct node *n_ptr)
+{
+       return (n_ptr && (n_ptr->last_router >= 0));
+}
+
+int node_is_up(struct node *n_ptr)
+{
+       return (node_has_active_links(n_ptr) || node_has_active_routes(n_ptr));
+}
+
+struct node *node_attach_link(struct link *l_ptr)
+{
+       struct node *n_ptr = node_find(l_ptr->addr);
+
+       if (!n_ptr)
+               n_ptr = node_create(l_ptr->addr);
+        if (n_ptr) {
+               u32 bearer_id = l_ptr->b_ptr->identity;
+               char addr_string[16];
+
+                assert(bearer_id < MAX_BEARERS);
+                if (n_ptr->link_cnt >= 2) {
+                       char addr_string[16];
+
+                        err("Attempt to create third link to %s\n",
+                           addr_string_fill(addr_string, n_ptr->addr));
+                        return 0;
+                }
+
+                if (!n_ptr->links[bearer_id]) {
+                        n_ptr->links[bearer_id] = l_ptr;
+                        net.zones[tipc_zone(l_ptr->addr)]->links++;
+                        n_ptr->link_cnt++;
+                        return n_ptr;
+                }
+                err("Attempt to establish second link on <%s> to <%s> \n",
+                    l_ptr->b_ptr->publ.name, 
+                   addr_string_fill(addr_string, l_ptr->addr));
+        }
+       return 0;
+}
+
+void node_detach_link(struct node *n_ptr, struct link *l_ptr)
+{
+       n_ptr->links[l_ptr->b_ptr->identity] = 0;
+       net.zones[tipc_zone(l_ptr->addr)]->links--;
+       n_ptr->link_cnt--;
+}
+
+/*
+ * Routing table management - five cases to handle:
+ *
+ * 1: A link towards a zone/cluster external node comes up.
+ *    => Send a multicast message updating routing tables of all 
+ *    system nodes within own cluster that the new destination 
+ *    can be reached via this node. 
+ *    (node.establishedContact()=>cluster.multicastNewRoute())
+ *
+ * 2: A link towards a slave node comes up.
+ *    => Send a multicast message updating routing tables of all 
+ *    system nodes within own cluster that the new destination 
+ *    can be reached via this node. 
+ *    (node.establishedContact()=>cluster.multicastNewRoute())
+ *    => Send a  message to the slave node about existence 
+ *    of all system nodes within cluster:
+ *    (node.establishedContact()=>cluster.sendLocalRoutes())
+ *
+ * 3: A new cluster local system node becomes available.
+ *    => Send message(s) to this particular node containing
+ *    information about all cluster external and slave
+ *     nodes which can be reached via this node.
+ *    (node.establishedContact()==>network.sendExternalRoutes())
+ *    (node.establishedContact()==>network.sendSlaveRoutes())
+ *    => Send messages to all directly connected slave nodes 
+ *    containing information about the existence of the new node
+ *    (node.establishedContact()=>cluster.multicastNewRoute())
+ *    
+ * 4: The link towards a zone/cluster external node or slave
+ *    node goes down.
+ *    => Send a multcast message updating routing tables of all 
+ *    nodes within cluster that the new destination can not any
+ *    longer be reached via this node.
+ *    (node.lostAllLinks()=>cluster.bcastLostRoute())
+ *
+ * 5: A cluster local system node becomes unavailable.
+ *    => Remove all references to this node from the local
+ *    routing tables. Note: This is a completely node
+ *    local operation.
+ *    (node.lostAllLinks()=>network.removeAsRouter())
+ *    => Send messages to all directly connected slave nodes 
+ *    containing information about loss of the node
+ *    (node.establishedContact()=>cluster.multicastLostRoute())
+ *
+ */
+
+static void node_established_contact(struct node *n_ptr)
+{
+       struct cluster *c_ptr;
+
+       dbg("node_established_contact:-> %x\n", n_ptr->addr);
+       if (!node_has_active_routes(n_ptr)) { 
+               k_signal((Handler)named_node_up, n_ptr->addr);
+       }
+
+        /* Syncronize broadcast acks */
+        n_ptr->bclink.acked = bclink_get_last_sent();
+
+       if (is_slave(tipc_own_addr))
+               return;
+       if (!in_own_cluster(n_ptr->addr)) {
+               /* Usage case 1 (see above) */
+               c_ptr = cluster_find(tipc_own_addr);
+               if (!c_ptr)
+                       c_ptr = cluster_create(tipc_own_addr);
+                if (c_ptr)
+                        cluster_bcast_new_route(c_ptr, n_ptr->addr, 1, 
+                                               tipc_max_nodes);
+               return;
+       } 
+
+       c_ptr = n_ptr->owner;
+       if (is_slave(n_ptr->addr)) {
+               /* Usage case 2 (see above) */
+               cluster_bcast_new_route(c_ptr, n_ptr->addr, 1, tipc_max_nodes);
+               cluster_send_local_routes(c_ptr, n_ptr->addr);
+               return;
+       }
+
+       if (n_ptr->bclink.supported) {
+               nmap_add(&cluster_bcast_nodes, n_ptr->addr);
+               if (n_ptr->addr < tipc_own_addr)
+                       tipc_own_tag++;
+       }
+
+       /* Case 3 (see above) */
+       net_send_external_routes(n_ptr->addr);
+       cluster_send_slave_routes(c_ptr, n_ptr->addr);
+       cluster_bcast_new_route(c_ptr, n_ptr->addr, LOWEST_SLAVE,
+                               highest_allowed_slave);
+}
+
+static void node_lost_contact(struct node *n_ptr)
+{
+       struct cluster *c_ptr;
+       struct node_subscr *ns, *tns;
+       char addr_string[16];
+       u32 i;
+
+        /* Clean up broadcast reception remains */
+        n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
+        while (n_ptr->bclink.deferred_head) {
+                struct sk_buff* buf = n_ptr->bclink.deferred_head;
+                n_ptr->bclink.deferred_head = buf->next;
+                buf_discard(buf);
+        }
+        if (n_ptr->bclink.defragm) {
+                buf_discard(n_ptr->bclink.defragm);  
+                n_ptr->bclink.defragm = NULL;
+        }            
+        if (in_own_cluster(n_ptr->addr) && n_ptr->bclink.supported) { 
+                bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000));
+        }
+
+        /* Update routing tables */
+       if (is_slave(tipc_own_addr)) {
+               net_remove_as_router(n_ptr->addr);
+       } else {
+               if (!in_own_cluster(n_ptr->addr)) { 
+                       /* Case 4 (see above) */
+                       c_ptr = cluster_find(tipc_own_addr);
+                       cluster_bcast_lost_route(c_ptr, n_ptr->addr, 1,
+                                                tipc_max_nodes);
+               } else {
+                       /* Case 5 (see above) */
+                       c_ptr = cluster_find(n_ptr->addr);
+                       if (is_slave(n_ptr->addr)) {
+                               cluster_bcast_lost_route(c_ptr, n_ptr->addr, 1,
+                                                        tipc_max_nodes);
+                       } else {
+                               if (n_ptr->bclink.supported) {
+                                       nmap_remove(&cluster_bcast_nodes, 
+                                                   n_ptr->addr);
+                                       if (n_ptr->addr < tipc_own_addr)
+                                               tipc_own_tag--;
+                               }
+                               net_remove_as_router(n_ptr->addr);
+                               cluster_bcast_lost_route(c_ptr, n_ptr->addr,
+                                                        LOWEST_SLAVE,
+                                                        highest_allowed_slave);
+                       }
+               }
+       }
+       if (node_has_active_routes(n_ptr))
+               return;
+
+       info("Lost contact with %s\n", 
+            addr_string_fill(addr_string, n_ptr->addr));
+
+       /* Abort link changeover */
+       for (i = 0; i < MAX_BEARERS; i++) {
+               struct link *l_ptr = n_ptr->links[i];
+               if (!l_ptr) 
+                       continue;
+               l_ptr->reset_checkpoint = l_ptr->next_in_no;
+               l_ptr->exp_msg_count = 0;
+               link_reset_fragments(l_ptr);
+       }
+
+       /* Notify subscribers */
+       list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
+                ns->node = 0;
+               list_del_init(&ns->nodesub_list);
+               k_signal((Handler)ns->handle_node_down,
+                        (unsigned long)ns->usr_handle);
+       }
+}
+
+/**
+ * node_select_next_hop - find the next-hop node for a message
+ * 
+ * Called by when cluster local lookup has failed.
+ */
+
+struct node *node_select_next_hop(u32 addr, u32 selector)
+{
+       struct node *n_ptr;
+       u32 router_addr;
+
+        if (!addr_domain_valid(addr))
+                return 0;
+
+       /* Look for direct link to destination processsor */
+       n_ptr = node_find(addr);
+       if (n_ptr && node_has_active_links(n_ptr))
+                return n_ptr;
+
+       /* Cluster local system nodes *must* have direct links */
+       if (!is_slave(addr) && in_own_cluster(addr))
+               return 0;
+
+       /* Look for cluster local router with direct link to node */
+       router_addr = node_select_router(n_ptr, selector);
+       if (router_addr) 
+                return node_select(router_addr, selector);
+
+       /* Slave nodes can only be accessed within own cluster via a 
+          known router with direct link -- if no router was found,give up */
+       if (is_slave(addr))
+               return 0;
+
+       /* Inter zone/cluster -- find any direct link to remote cluster */
+       addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
+       n_ptr = net_select_remote_node(addr, selector);
+       if (n_ptr && node_has_active_links(n_ptr))
+                return n_ptr;
+
+       /* Last resort -- look for any router to anywhere in remote zone */
+       router_addr =  net_select_router(addr, selector);
+       if (router_addr) 
+                return node_select(router_addr, selector);
+
+        return 0;
+}
+
+/**
+ * node_select_router - select router to reach specified node
+ * 
+ * Uses a deterministic and fair algorithm for selecting router node. 
+ */
+
+u32 node_select_router(struct node *n_ptr, u32 ref)
+{
+       u32 ulim;
+       u32 mask;
+       u32 start;
+       u32 r;
+
+        if (!n_ptr)
+                return 0;
+
+       if (n_ptr->last_router < 0)
+               return 0;
+       ulim = ((n_ptr->last_router + 1) * 32) - 1;
+
+       /* Start entry must be random */
+       mask = tipc_max_nodes;
+       while (mask > ulim)
+               mask >>= 1;
+       start = ref & mask;
+       r = start;
+
+       /* Lookup upwards with wrap-around */
+       do {
+               if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
+                       break;
+       } while (++r <= ulim);
+       if (r > ulim) {
+               r = 1;
+               do {
+                       if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
+                               break;
+               } while (++r < start);
+               assert(r != start);
+       }
+       assert(r && (r <= ulim));
+       return tipc_addr(own_zone(), own_cluster(), r);
+}
+
+void node_add_router(struct node *n_ptr, u32 router)
+{
+       u32 r_num = tipc_node(router);
+
+       n_ptr->routers[r_num / 32] = 
+               ((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]);
+       n_ptr->last_router = tipc_max_nodes / 32;
+       while ((--n_ptr->last_router >= 0) && 
+              !n_ptr->routers[n_ptr->last_router]);
+}
+
+void node_remove_router(struct node *n_ptr, u32 router)
+{
+       u32 r_num = tipc_node(router);
+
+       if (n_ptr->last_router < 0)
+               return;         /* No routes */
+
+       n_ptr->routers[r_num / 32] =
+               ((~(1 << (r_num % 32))) & (n_ptr->routers[r_num / 32]));
+       n_ptr->last_router = tipc_max_nodes / 32;
+       while ((--n_ptr->last_router >= 0) && 
+              !n_ptr->routers[n_ptr->last_router]);
+
+       if (!node_is_up(n_ptr))
+               node_lost_contact(n_ptr);
+}
+
+#if 0
+void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
+{
+       u32 i;
+
+       tipc_printf(buf, "\n\n%s", str);
+       for (i = 0; i < MAX_BEARERS; i++) {
+               if (!n_ptr->links[i]) 
+                       continue;
+               tipc_printf(buf, "Links[%u]: %x, ", i, n_ptr->links[i]);
+       }
+       tipc_printf(buf, "Active links: [%x,%x]\n",
+                   n_ptr->active_links[0], n_ptr->active_links[1]);
+}
+#endif
+
+u32 tipc_available_nodes(const u32 domain)
+{
+       struct node *n_ptr;
+       u32 cnt = 0;
+
+       for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
+               if (!in_scope(domain, n_ptr->addr))
+                       continue;
+               if (node_is_up(n_ptr))
+                       cnt++;
+       }
+       return cnt;
+}
+
+struct sk_buff *node_get_nodes(const void *req_tlv_area, int req_tlv_space)
+{
+       u32 domain;
+       struct sk_buff *buf;
+       struct node *n_ptr;
+        struct tipc_node_info node_info;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       domain = *(u32 *)TLV_DATA(req_tlv_area);
+       domain = ntohl(domain);
+       if (!addr_domain_valid(domain))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (network address)");
+
+        if (!nodes)
+                return cfg_reply_none();
+
+       /* For now, get space for all other nodes 
+          (will need to modify this when slave nodes are supported */
+
+       buf = cfg_reply_alloc(TLV_SPACE(sizeof(node_info)) *
+                           (tipc_max_nodes - 1));
+       if (!buf)
+               return NULL;
+
+       /* Add TLVs for all nodes in scope */
+
+       for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
+               if (!in_scope(domain, n_ptr->addr))
+                       continue;
+                node_info.addr = htonl(n_ptr->addr);
+                node_info.up = htonl(node_is_up(n_ptr));
+               cfg_append_tlv(buf, TIPC_TLV_NODE_INFO, 
+                              &node_info, sizeof(node_info));
+       }
+
+       return buf;
+}
+
+struct sk_buff *node_get_links(const void *req_tlv_area, int req_tlv_space)
+{
+       u32 domain;
+       struct sk_buff *buf;
+       struct node *n_ptr;
+        struct tipc_link_info link_info;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       domain = *(u32 *)TLV_DATA(req_tlv_area);
+       domain = ntohl(domain);
+       if (!addr_domain_valid(domain))
+               return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
+                                             " (network address)");
+
+        if (!nodes)
+                return cfg_reply_none();
+
+       /* For now, get space for 2 links to all other nodes + bcast link 
+          (will need to modify this when slave nodes are supported */
+
+       buf = cfg_reply_alloc(TLV_SPACE(sizeof(link_info)) *
+                           (2 * (tipc_max_nodes - 1) + 1));
+       if (!buf)
+               return NULL;
+
+       /* Add TLV for broadcast link */
+
+        link_info.dest = tipc_own_addr & 0xfffff00;
+       link_info.dest = htonl(link_info.dest);
+        link_info.up = htonl(1);
+        sprintf(link_info.str, bc_link_name);
+       cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
+
+       /* Add TLVs for any other links in scope */
+
+       for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
+                u32 i;
+
+               if (!in_scope(domain, n_ptr->addr))
+                       continue;
+                for (i = 0; i < MAX_BEARERS; i++) {
+                        if (!n_ptr->links[i]) 
+                                continue;
+                        link_info.dest = htonl(n_ptr->addr);
+                        link_info.up = htonl(link_is_up(n_ptr->links[i]));
+                        strcpy(link_info.str, n_ptr->links[i]->name);
+                       cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, 
+                                      &link_info, sizeof(link_info));
+                }
+       }
+
+       return buf;
+}
diff --git a/net/tipc/node.h b/net/tipc/node.h
new file mode 100644 (file)
index 0000000..b39442b
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * net/tipc/node.h: Include file for TIPC node management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NODE_H
+#define _TIPC_NODE_H
+
+#include "node_subscr.h"
+#include "addr.h"
+#include "cluster.h"
+#include "bearer.h"
+
+/**
+ * struct node - TIPC node structure
+ * @addr: network address of node
+ * @lock: spinlock governing access to structure
+ * @owner: pointer to cluster that node belongs to
+ * @next: pointer to next node in sorted list of cluster's nodes
+ * @nsub: list of "node down" subscriptions monitoring node
+ * @active_links: pointers to active links to node
+ * @links: pointers to all links to node
+ * @link_cnt: number of links to node
+ * @permit_changeover: non-zero if node has redundant links to this system
+ * @routers: bitmap (used for multicluster communication)
+ * @last_router: (used for multicluster communication)
+ * @bclink: broadcast-related info
+ *    @supported: non-zero if node supports TIPC b'cast capability
+ *    @acked: sequence # of last outbound b'cast message acknowledged by node
+ *    @last_in: sequence # of last in-sequence b'cast message received from node
+ *    @gap_after: sequence # of last message not requiring a NAK request
+ *    @gap_to: sequence # of last message requiring a NAK request
+ *    @nack_sync: counter that determines when NAK requests should be sent
+ *    @deferred_head: oldest OOS b'cast message received from node
+ *    @deferred_tail: newest OOS b'cast message received from node
+ *    @defragm: list of partially reassembled b'cast message fragments from node
+ */
+struct node {
+       u32 addr;
+       spinlock_t lock;
+       struct cluster *owner;
+       struct node *next;
+       struct list_head nsub;
+       struct link *active_links[2];
+       struct link *links[MAX_BEARERS];
+       int link_cnt;
+       int permit_changeover;
+       u32 routers[512/32];
+       int last_router;
+       struct {
+               int supported;
+               u32 acked;
+               u32 last_in;
+               u32 gap_after; 
+               u32 gap_to; 
+               u32 nack_sync;
+               struct sk_buff *deferred_head;
+               struct sk_buff *deferred_tail;
+               struct sk_buff *defragm;
+       } bclink;
+};
+
+extern struct node *nodes;
+extern u32 tipc_own_tag;
+
+struct node *node_create(u32 addr);
+void node_delete(struct node *n_ptr);
+struct node *node_attach_link(struct link *l_ptr);
+void node_detach_link(struct node *n_ptr, struct link *l_ptr);
+void node_link_down(struct node *n_ptr, struct link *l_ptr);
+void node_link_up(struct node *n_ptr, struct link *l_ptr);
+int node_has_active_links(struct node *n_ptr);
+int node_has_redundant_links(struct node *n_ptr);
+u32 node_select_router(struct node *n_ptr, u32 ref);
+struct node *node_select_next_hop(u32 addr, u32 selector);
+int node_is_up(struct node *n_ptr);
+void node_add_router(struct node *n_ptr, u32 router);
+void node_remove_router(struct node *n_ptr, u32 router);
+struct sk_buff *node_get_links(const void *req_tlv_area, int req_tlv_space);
+struct sk_buff *node_get_nodes(const void *req_tlv_area, int req_tlv_space);
+
+static inline struct node *node_find(u32 addr)
+{
+       if (likely(in_own_cluster(addr)))
+               return local_nodes[tipc_node(addr)];
+       else if (addr_domain_valid(addr)) {
+               struct cluster *c_ptr = cluster_find(addr);
+
+               if (c_ptr)
+                       return c_ptr->nodes[tipc_node(addr)];
+       }
+       return 0;
+}
+
+static inline struct node *node_select(u32 addr, u32 selector)
+{
+       if (likely(in_own_cluster(addr)))
+               return local_nodes[tipc_node(addr)];
+       return node_select_next_hop(addr, selector);
+}
+
+static inline void node_lock(struct node *n_ptr)
+{
+       spin_lock_bh(&n_ptr->lock);
+}
+
+static inline void node_unlock(struct node *n_ptr)
+{
+       spin_unlock_bh(&n_ptr->lock);
+}
+
+#endif
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c
new file mode 100644 (file)
index 0000000..7937592
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * net/tipc/node_subscr.c: TIPC "node down" subscription handling
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "node_subscr.h"
+#include "node.h"
+#include "addr.h"
+
+/**
+ * nodesub_subscribe - create "node down" subscription for specified node
+ */
+
+void nodesub_subscribe(struct node_subscr *node_sub, u32 addr, 
+                      void *usr_handle, net_ev_handler handle_down)
+{
+       node_sub->node = 0;
+       if (addr == tipc_own_addr)
+               return;
+       if (!addr_node_valid(addr)) {
+               warn("node_subscr with illegal %x\n", addr);
+               return;
+       }
+
+       node_sub->handle_node_down = handle_down;
+       node_sub->usr_handle = usr_handle;
+       node_sub->node = node_find(addr);
+       assert(node_sub->node);
+       node_lock(node_sub->node);
+       list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub);
+       node_unlock(node_sub->node);
+}
+
+/**
+ * nodesub_unsubscribe - cancel "node down" subscription (if any)
+ */
+
+void nodesub_unsubscribe(struct node_subscr *node_sub)
+{
+       if (!node_sub->node)
+               return;
+
+       node_lock(node_sub->node);
+       list_del_init(&node_sub->nodesub_list);
+       node_unlock(node_sub->node);
+}
diff --git a/net/tipc/node_subscr.h b/net/tipc/node_subscr.h
new file mode 100644 (file)
index 0000000..a3b87ac
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * net/tipc/node_subscr.h: Include file for TIPC "node down" subscription handling
+ * 
+ * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_NODE_SUBSCR_H
+#define _TIPC_NODE_SUBSCR_H
+
+#include "addr.h"
+
+typedef void (*net_ev_handler) (void *usr_handle);
+
+/**
+ * struct node_subscr - "node down" subscription entry
+ * @node: ptr to node structure of interest (or NULL, if none)
+ * @handle_node_down: routine to invoke when node fails
+ * @usr_handle: argument to pass to routine when node fails
+ * @nodesub_list: adjacent entries in list of subscriptions for the node
+ */
+
+struct node_subscr {
+       struct node *node;
+       net_ev_handler handle_node_down;
+       void *usr_handle;
+       struct list_head nodesub_list;
+};
+
+void nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
+                      void *usr_handle, net_ev_handler handle_down);
+void nodesub_unsubscribe(struct node_subscr *node_sub);
+
+#endif
diff --git a/net/tipc/port.c b/net/tipc/port.c
new file mode 100644 (file)
index 0000000..66caca7
--- /dev/null
@@ -0,0 +1,1708 @@
+/*
+ * net/tipc/port.c: TIPC port code
+ * 
+ * Copyright (c) 1992-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "config.h"
+#include "dbg.h"
+#include "port.h"
+#include "addr.h"
+#include "link.h"
+#include "node.h"
+#include "port.h"
+#include "name_table.h"
+#include "user_reg.h"
+#include "msg.h"
+#include "bcast.h"
+
+/* Connection management: */
+#define PROBING_INTERVAL 3600000       /* [ms] => 1 h */
+#define CONFIRMED 0
+#define PROBING 1
+
+#define MAX_REJECT_SIZE 1024
+
+static struct sk_buff *msg_queue_head = 0;
+static struct sk_buff *msg_queue_tail = 0;
+
+spinlock_t port_list_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
+
+LIST_HEAD(ports);
+static void port_handle_node_down(unsigned long ref);
+static struct sk_buff* port_build_self_abort_msg(struct port *,u32 err);
+static struct sk_buff* port_build_peer_abort_msg(struct port *,u32 err);
+static void port_timeout(unsigned long ref);
+
+
+static inline u32 port_peernode(struct port *p_ptr)
+{
+       return msg_destnode(&p_ptr->publ.phdr);
+}
+
+static inline u32 port_peerport(struct port *p_ptr)
+{
+       return msg_destport(&p_ptr->publ.phdr);
+}
+
+static inline u32 port_out_seqno(struct port *p_ptr)
+{
+       return msg_transp_seqno(&p_ptr->publ.phdr);
+}
+
+static inline void port_set_out_seqno(struct port *p_ptr, u32 seqno) 
+{
+       msg_set_transp_seqno(&p_ptr->publ.phdr,seqno);
+}
+
+static inline void port_incr_out_seqno(struct port *p_ptr)
+{
+       struct tipc_msg *m = &p_ptr->publ.phdr;
+
+       if (likely(!msg_routed(m)))
+               return;
+       msg_set_transp_seqno(m, (msg_transp_seqno(m) + 1));
+}
+
+/**
+ * tipc_multicast - send a multicast message to local and remote destinations
+ */
+
+int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain,
+                  u32 num_sect, struct iovec const *msg_sect)
+{
+       struct tipc_msg *hdr;
+       struct sk_buff *buf;
+       struct sk_buff *ibuf = NULL;
+       struct port_list dports = {0, NULL, };
+       struct port *oport = port_deref(ref);
+       int ext_targets;
+       int res;
+
+       if (unlikely(!oport))
+               return -EINVAL;
+
+       /* Create multicast message */
+
+       hdr = &oport->publ.phdr;
+       msg_set_type(hdr, TIPC_MCAST_MSG);
+       msg_set_nametype(hdr, seq->type);
+       msg_set_namelower(hdr, seq->lower);
+       msg_set_nameupper(hdr, seq->upper);
+       msg_set_hdr_sz(hdr, MCAST_H_SIZE);
+       res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
+                       !oport->user_port, &buf);
+       if (unlikely(!buf))
+               return res;
+
+       /* Figure out where to send multicast message */
+
+       ext_targets = nametbl_mc_translate(seq->type, seq->lower, seq->upper,
+                                          TIPC_NODE_SCOPE, &dports);
+       
+       /* Send message to destinations (duplicate it only if necessary) */ 
+
+       if (ext_targets) {
+               if (dports.count != 0) {
+                       ibuf = skb_copy(buf, GFP_ATOMIC);
+                       if (ibuf == NULL) {
+                               port_list_free(&dports);
+                               buf_discard(buf);
+                               return -ENOMEM;
+                       }
+               }
+               res = bclink_send_msg(buf);
+               if ((res < 0) && (dports.count != 0)) {
+                       buf_discard(ibuf);
+               }
+       } else {
+               ibuf = buf;
+       }
+
+       if (res >= 0) {
+               if (ibuf)
+                       port_recv_mcast(ibuf, &dports);
+       } else {
+               port_list_free(&dports);
+       }
+       return res;
+}
+
+/**
+ * port_recv_mcast - deliver multicast message to all destination ports
+ * 
+ * If there is no port list, perform a lookup to create one
+ */
+
+void port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
+{
+       struct tipc_msg* msg;
+       struct port_list dports = {0, NULL, };
+       struct port_list *item = dp;
+       int cnt = 0;
+
+       assert(buf);
+       msg = buf_msg(buf);
+
+       /* Create destination port list, if one wasn't supplied */
+
+       if (dp == NULL) {
+               nametbl_mc_translate(msg_nametype(msg),
+                                    msg_namelower(msg),
+                                    msg_nameupper(msg),
+                                    TIPC_CLUSTER_SCOPE,
+                                    &dports);
+               item = dp = &dports;
+       }
+
+       /* Deliver a copy of message to each destination port */
+
+       if (dp->count != 0) {
+               if (dp->count == 1) {
+                       msg_set_destport(msg, dp->ports[0]);
+                       port_recv_msg(buf);
+                       port_list_free(dp);
+                       return;
+               }
+               for (; cnt < dp->count; cnt++) {
+                       int index = cnt % PLSIZE;
+                       struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
+
+                       if (b == NULL) {
+                               warn("Buffer allocation failure\n");
+                               msg_dbg(msg, "LOST:");
+                               goto exit;
+                       }
+                       if ((index == 0) && (cnt != 0)) {
+                               item = item->next;
+                       }
+                       msg_set_destport(buf_msg(b),item->ports[index]);
+                       port_recv_msg(b);
+               }
+       }
+exit:
+       buf_discard(buf);
+       port_list_free(dp);
+}
+
+/**
+ * tipc_createport_raw - create a native TIPC port
+ * 
+ * Returns local port reference
+ */
+
+u32 tipc_createport_raw(void *usr_handle,
+                       u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
+                       void (*wakeup)(struct tipc_port *),
+                       const u32 importance)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       u32 ref;
+
+       p_ptr = kmalloc(sizeof(*p_ptr), GFP_ATOMIC);
+       if (p_ptr == NULL) {
+               warn("Memory squeeze; failed to create port\n");
+               return 0;
+       }
+       memset(p_ptr, 0, sizeof(*p_ptr));
+       ref = ref_acquire(p_ptr, &p_ptr->publ.lock);
+       if (!ref) {
+               warn("Reference Table Exhausted\n");
+               kfree(p_ptr);
+               return 0;
+       }
+
+       port_lock(ref);
+       p_ptr->publ.ref = ref;
+       msg = &p_ptr->publ.phdr;
+       msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
+       msg_set_orignode(msg, tipc_own_addr);
+       msg_set_prevnode(msg, tipc_own_addr);
+       msg_set_origport(msg, ref);
+       msg_set_importance(msg,importance);
+       p_ptr->last_in_seqno = 41;
+       p_ptr->sent = 1;
+       p_ptr->publ.usr_handle = usr_handle;
+       INIT_LIST_HEAD(&p_ptr->wait_list);
+       INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
+       p_ptr->congested_link = 0;
+       p_ptr->max_pkt = MAX_PKT_DEFAULT;
+       p_ptr->dispatcher = dispatcher;
+       p_ptr->wakeup = wakeup;
+       p_ptr->user_port = 0;
+       k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
+       spin_lock_bh(&port_list_lock);
+       INIT_LIST_HEAD(&p_ptr->publications);
+       INIT_LIST_HEAD(&p_ptr->port_list);
+       list_add_tail(&p_ptr->port_list, &ports);
+       spin_unlock_bh(&port_list_lock);
+       port_unlock(p_ptr);
+       return ref;
+}
+
+int tipc_deleteport(u32 ref)
+{
+       struct port *p_ptr;
+       struct sk_buff *buf = 0;
+
+       tipc_withdraw(ref, 0, 0);
+       p_ptr = port_lock(ref);
+       if (!p_ptr) 
+               return -EINVAL;
+
+       ref_discard(ref);
+       port_unlock(p_ptr);
+
+       k_cancel_timer(&p_ptr->timer);
+       if (p_ptr->publ.connected) {
+               buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
+               nodesub_unsubscribe(&p_ptr->subscription);
+       }
+       if (p_ptr->user_port) {
+               reg_remove_port(p_ptr->user_port);
+               kfree(p_ptr->user_port);
+       }
+
+       spin_lock_bh(&port_list_lock);
+       list_del(&p_ptr->port_list);
+       list_del(&p_ptr->wait_list);
+       spin_unlock_bh(&port_list_lock);
+       k_term_timer(&p_ptr->timer);
+       kfree(p_ptr);
+       dbg("Deleted port %u\n", ref);
+       net_route_msg(buf);
+       return TIPC_OK;
+}
+
+/**
+ * tipc_get_port() - return port associated with 'ref'
+ * 
+ * Note: Port is not locked.
+ */
+
+struct tipc_port *tipc_get_port(const u32 ref)
+{
+       return (struct tipc_port *)ref_deref(ref);
+}
+
+/**
+ * tipc_get_handle - return user handle associated to port 'ref'
+ */
+
+void *tipc_get_handle(const u32 ref)
+{
+       struct port *p_ptr;
+       void * handle;
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return 0;
+       handle = p_ptr->publ.usr_handle;
+       port_unlock(p_ptr);
+       return handle;
+}
+
+static inline int port_unreliable(struct port *p_ptr)
+{
+       return msg_src_droppable(&p_ptr->publ.phdr);
+}
+
+int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
+{
+       struct port *p_ptr;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       *isunreliable = port_unreliable(p_ptr);
+       spin_unlock_bh(p_ptr->publ.lock);
+       return TIPC_OK;
+}
+
+int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
+{
+       struct port *p_ptr;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       msg_set_src_droppable(&p_ptr->publ.phdr, (isunreliable != 0));
+       port_unlock(p_ptr);
+       return TIPC_OK;
+}
+
+static inline int port_unreturnable(struct port *p_ptr)
+{
+       return msg_dest_droppable(&p_ptr->publ.phdr);
+}
+
+int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
+{
+       struct port *p_ptr;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       *isunrejectable = port_unreturnable(p_ptr);
+       spin_unlock_bh(p_ptr->publ.lock);
+       return TIPC_OK;
+}
+
+int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
+{
+       struct port *p_ptr;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       msg_set_dest_droppable(&p_ptr->publ.phdr, (isunrejectable != 0));
+       port_unlock(p_ptr);
+       return TIPC_OK;
+}
+
+/* 
+ * port_build_proto_msg(): build a port level protocol 
+ * or a connection abortion message. Called with 
+ * tipc_port lock on.
+ */
+static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
+                                           u32 origport, u32 orignode,
+                                           u32 usr, u32 type, u32 err, 
+                                           u32 seqno, u32 ack)
+{
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+       
+       buf = buf_acquire(LONG_H_SIZE);
+       if (buf) {
+               msg = buf_msg(buf);
+               msg_init(msg, usr, type, err, LONG_H_SIZE, destnode);
+               msg_set_destport(msg, destport);
+               msg_set_origport(msg, origport);
+               msg_set_destnode(msg, destnode);
+               msg_set_orignode(msg, orignode);
+               msg_set_transp_seqno(msg, seqno);
+               msg_set_msgcnt(msg, ack);
+               msg_dbg(msg, "PORT>SEND>:");
+       }
+       return buf;
+}
+
+int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz)
+{
+       msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr));
+       msg_set_options(&tp_ptr->phdr, opt, sz);
+       return TIPC_OK;
+}
+
+int tipc_reject_msg(struct sk_buff *buf, u32 err)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       struct sk_buff *rbuf;
+       struct tipc_msg *rmsg;
+       int hdr_sz;
+       u32 imp = msg_importance(msg);
+       u32 data_sz = msg_data_sz(msg);
+
+       if (data_sz > MAX_REJECT_SIZE)
+               data_sz = MAX_REJECT_SIZE;
+       if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE))
+               imp++;
+       msg_dbg(msg, "port->rej: ");
+
+       /* discard rejected message if it shouldn't be returned to sender */
+       if (msg_errcode(msg) || msg_dest_droppable(msg)) {
+               buf_discard(buf);
+               return data_sz;
+       }
+
+       /* construct rejected message */
+       if (msg_mcast(msg))
+               hdr_sz = MCAST_H_SIZE;
+       else
+               hdr_sz = LONG_H_SIZE;
+       rbuf = buf_acquire(data_sz + hdr_sz);
+       if (rbuf == NULL) {
+               buf_discard(buf);
+               return data_sz;
+       }
+       rmsg = buf_msg(rbuf);
+       msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg));
+       msg_set_destport(rmsg, msg_origport(msg));
+       msg_set_prevnode(rmsg, tipc_own_addr);
+       msg_set_origport(rmsg, msg_destport(msg));
+       if (msg_short(msg))
+               msg_set_orignode(rmsg, tipc_own_addr);
+       else
+               msg_set_orignode(rmsg, msg_destnode(msg));
+       msg_set_size(rmsg, data_sz + hdr_sz); 
+       msg_set_nametype(rmsg, msg_nametype(msg));
+       msg_set_nameinst(rmsg, msg_nameinst(msg));
+       memcpy(rbuf->data + hdr_sz, msg_data(msg), data_sz);
+
+       /* send self-abort message when rejecting on a connected port */
+       if (msg_connected(msg)) {
+               struct sk_buff *abuf = 0;
+               struct port *p_ptr = port_lock(msg_destport(msg));
+
+               if (p_ptr) {
+                       if (p_ptr->publ.connected)
+                               abuf = port_build_self_abort_msg(p_ptr, err);
+                       port_unlock(p_ptr);
+               }
+               net_route_msg(abuf);
+       }
+
+       /* send rejected message */
+       buf_discard(buf);
+       net_route_msg(rbuf);
+       return data_sz;
+}
+
+int port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
+                        struct iovec const *msg_sect, u32 num_sect,
+                        int err)
+{
+       struct sk_buff *buf;
+       int res;
+
+       res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE, 
+                       !p_ptr->user_port, &buf);
+       if (!buf)
+               return res;
+
+       return tipc_reject_msg(buf, err);
+}
+
+static void port_timeout(unsigned long ref)
+{
+       struct port *p_ptr = port_lock(ref);
+       struct sk_buff *buf = 0;
+
+       if (!p_ptr || !p_ptr->publ.connected)
+               return;
+
+       /* Last probe answered ? */
+       if (p_ptr->probing_state == PROBING) {
+               buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
+       } else {
+               buf = port_build_proto_msg(port_peerport(p_ptr),
+                                          port_peernode(p_ptr),
+                                          p_ptr->publ.ref,
+                                          tipc_own_addr,
+                                          CONN_MANAGER,
+                                          CONN_PROBE,
+                                          TIPC_OK, 
+                                          port_out_seqno(p_ptr),
+                                          0);
+               port_incr_out_seqno(p_ptr);
+               p_ptr->probing_state = PROBING;
+               k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
+       }
+       port_unlock(p_ptr);
+       net_route_msg(buf);
+}
+
+
+static void port_handle_node_down(unsigned long ref)
+{
+       struct port *p_ptr = port_lock(ref);
+       struct sk_buff* buf = 0;
+
+       if (!p_ptr)
+               return;
+       buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
+       port_unlock(p_ptr);
+       net_route_msg(buf);
+}
+
+
+static struct sk_buff *port_build_self_abort_msg(struct port *p_ptr, u32 err)
+{
+       u32 imp = msg_importance(&p_ptr->publ.phdr);
+
+       if (!p_ptr->publ.connected)
+               return 0;
+       if (imp < TIPC_CRITICAL_IMPORTANCE)
+               imp++;
+       return port_build_proto_msg(p_ptr->publ.ref,
+                                   tipc_own_addr,
+                                   port_peerport(p_ptr),
+                                   port_peernode(p_ptr),
+                                   imp,
+                                   TIPC_CONN_MSG,
+                                   err, 
+                                   p_ptr->last_in_seqno + 1,
+                                   0);
+}
+
+
+static struct sk_buff *port_build_peer_abort_msg(struct port *p_ptr, u32 err)
+{
+       u32 imp = msg_importance(&p_ptr->publ.phdr);
+
+       if (!p_ptr->publ.connected)
+               return 0;
+       if (imp < TIPC_CRITICAL_IMPORTANCE)
+               imp++;
+       return port_build_proto_msg(port_peerport(p_ptr),
+                                   port_peernode(p_ptr),
+                                   p_ptr->publ.ref,
+                                   tipc_own_addr,
+                                   imp,
+                                   TIPC_CONN_MSG,
+                                   err, 
+                                   port_out_seqno(p_ptr),
+                                   0);
+}
+
+void port_recv_proto_msg(struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       struct port *p_ptr = port_lock(msg_destport(msg));
+       u32 err = TIPC_OK;
+       struct sk_buff *r_buf = 0;
+       struct sk_buff *abort_buf = 0;
+
+       msg_dbg(msg, "PORT<RECV<:");
+
+       if (!p_ptr) {
+               err = TIPC_ERR_NO_PORT;
+       } else if (p_ptr->publ.connected) {
+               if (port_peernode(p_ptr) != msg_orignode(msg))
+                       err = TIPC_ERR_NO_PORT;
+               if (port_peerport(p_ptr) != msg_origport(msg))
+                       err = TIPC_ERR_NO_PORT;
+               if (!err && msg_routed(msg)) {
+                       u32 seqno = msg_transp_seqno(msg);
+                       u32 myno =  ++p_ptr->last_in_seqno;
+                       if (seqno != myno) {
+                               err = TIPC_ERR_NO_PORT;
+                               abort_buf = port_build_self_abort_msg(p_ptr, err);
+                       }
+               }
+               if (msg_type(msg) == CONN_ACK) {
+                       int wakeup = port_congested(p_ptr) && 
+                                    p_ptr->publ.congested &&
+                                    p_ptr->wakeup;
+                       p_ptr->acked += msg_msgcnt(msg);
+                       if (port_congested(p_ptr))
+                               goto exit;
+                       p_ptr->publ.congested = 0;
+                       if (!wakeup)
+                               goto exit;
+                       p_ptr->wakeup(&p_ptr->publ);
+                       goto exit;
+               }
+       } else if (p_ptr->publ.published) {
+               err = TIPC_ERR_NO_PORT;
+       }
+       if (err) {
+               r_buf = port_build_proto_msg(msg_origport(msg),
+                                            msg_orignode(msg), 
+                                            msg_destport(msg), 
+                                            tipc_own_addr,
+                                            DATA_HIGH,
+                                            TIPC_CONN_MSG,
+                                            err,
+                                            0,
+                                            0);
+               goto exit;
+       }
+
+       /* All is fine */
+       if (msg_type(msg) == CONN_PROBE) {
+               r_buf = port_build_proto_msg(msg_origport(msg), 
+                                            msg_orignode(msg), 
+                                            msg_destport(msg), 
+                                            tipc_own_addr, 
+                                            CONN_MANAGER,
+                                            CONN_PROBE_REPLY,
+                                            TIPC_OK,
+                                            port_out_seqno(p_ptr),
+                                            0);
+       }
+       p_ptr->probing_state = CONFIRMED;
+       port_incr_out_seqno(p_ptr);
+exit:
+       if (p_ptr)
+               port_unlock(p_ptr);
+       net_route_msg(r_buf);
+       net_route_msg(abort_buf);
+       buf_discard(buf);
+}
+
+static void port_print(struct port *p_ptr, struct print_buf *buf, int full_id)
+{
+        struct publication *publ;
+
+       if (full_id)
+               tipc_printf(buf, "<%u.%u.%u:%u>:", 
+                           tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
+                            tipc_node(tipc_own_addr), p_ptr->publ.ref);
+       else
+               tipc_printf(buf, "%-10u:", p_ptr->publ.ref);
+
+        if (p_ptr->publ.connected) {
+                u32 dport = port_peerport(p_ptr);
+                u32 destnode = port_peernode(p_ptr);
+
+                tipc_printf(buf, " connected to <%u.%u.%u:%u>",
+                            tipc_zone(destnode), tipc_cluster(destnode),
+                            tipc_node(destnode), dport);
+                if (p_ptr->publ.conn_type != 0)
+                        tipc_printf(buf, " via {%u,%u}",
+                                    p_ptr->publ.conn_type,
+                                    p_ptr->publ.conn_instance);
+        }
+        else if (p_ptr->publ.published) {
+                tipc_printf(buf, " bound to");
+                list_for_each_entry(publ, &p_ptr->publications, pport_list) {
+                       if (publ->lower == publ->upper)
+                               tipc_printf(buf, " {%u,%u}", publ->type,
+                                           publ->lower);
+                       else
+                               tipc_printf(buf, " {%u,%u,%u}", publ->type, 
+                                           publ->lower, publ->upper);
+                }
+        }
+        tipc_printf(buf, "\n");
+}
+
+#define MAX_PORT_QUERY 32768
+
+struct sk_buff *port_get_ports(void)
+{
+       struct sk_buff *buf;
+       struct tlv_desc *rep_tlv;
+       struct print_buf pb;
+       struct port *p_ptr;
+       int str_len;
+
+       buf = cfg_reply_alloc(TLV_SPACE(MAX_PORT_QUERY));
+       if (!buf)
+               return NULL;
+       rep_tlv = (struct tlv_desc *)buf->data;
+
+       printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_QUERY);
+       spin_lock_bh(&port_list_lock);
+       list_for_each_entry(p_ptr, &ports, port_list) {
+               spin_lock_bh(p_ptr->publ.lock);
+               port_print(p_ptr, &pb, 0);
+               spin_unlock_bh(p_ptr->publ.lock);
+       }
+       spin_unlock_bh(&port_list_lock);
+       str_len = printbuf_validate(&pb);
+
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
+#if 0
+
+#define MAX_PORT_STATS 2000
+
+struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space)
+{
+       u32 ref;
+       struct port *p_ptr;
+       struct sk_buff *buf;
+       struct tlv_desc *rep_tlv;
+       struct print_buf pb;
+       int str_len;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_PORT_REF))
+               return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       ref = *(u32 *)TLV_DATA(req_tlv_area);
+       ref = ntohl(ref);
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return cfg_reply_error_string("port not found");
+
+       buf = cfg_reply_alloc(TLV_SPACE(MAX_PORT_STATS));
+       if (!buf) {
+               port_unlock(p_ptr);
+               return NULL;
+       }
+       rep_tlv = (struct tlv_desc *)buf->data;
+
+       printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_STATS);
+       port_print(p_ptr, &pb, 1);
+       /* NEED TO FILL IN ADDITIONAL PORT STATISTICS HERE */
+       port_unlock(p_ptr);
+       str_len = printbuf_validate(&pb);
+
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
+#endif
+
+void port_reinit(void)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+
+       spin_lock_bh(&port_list_lock);
+       list_for_each_entry(p_ptr, &ports, port_list) {
+               msg = &p_ptr->publ.phdr;
+               if (msg_orignode(msg) == tipc_own_addr)
+                       break;
+               msg_set_orignode(msg, tipc_own_addr);
+       }
+       spin_unlock_bh(&port_list_lock);
+}
+
+
+/*
+ *  port_dispatcher_sigh(): Signal handler for messages destinated
+ *                          to the tipc_port interface.
+ */
+
+static void port_dispatcher_sigh(void *dummy)
+{
+       struct sk_buff *buf;
+
+       spin_lock_bh(&queue_lock);
+       buf = msg_queue_head;
+       msg_queue_head = 0;
+       spin_unlock_bh(&queue_lock);
+
+       while (buf) {
+               struct port *p_ptr;
+               struct user_port *up_ptr;
+               struct tipc_portid orig;
+               struct tipc_name_seq dseq;
+               void *usr_handle;
+               int connected;
+               int published;
+
+               struct sk_buff *next = buf->next;
+               struct tipc_msg *msg = buf_msg(buf);
+               u32 dref = msg_destport(msg);
+               
+               p_ptr = port_lock(dref);
+               if (!p_ptr) {
+                       /* Port deleted while msg in queue */
+                       tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+                       buf = next;
+                       continue;
+               }
+               orig.ref = msg_origport(msg);
+               orig.node = msg_orignode(msg);
+               up_ptr = p_ptr->user_port;
+               usr_handle = up_ptr->usr_handle;
+               connected = p_ptr->publ.connected;
+               published = p_ptr->publ.published;
+
+               if (unlikely(msg_errcode(msg)))
+                       goto err;
+
+               switch (msg_type(msg)) {
+               
+               case TIPC_CONN_MSG:{
+                               tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
+                               u32 peer_port = port_peerport(p_ptr);
+                               u32 peer_node = port_peernode(p_ptr);
+
+                               spin_unlock_bh(p_ptr->publ.lock);
+                               if (unlikely(!connected)) {
+                                       if (unlikely(published))
+                                               goto reject;
+                                       tipc_connect2port(dref,&orig);
+                               }
+                               if (unlikely(msg_origport(msg) != peer_port))
+                                       goto reject;
+                               if (unlikely(msg_orignode(msg) != peer_node))
+                                       goto reject;
+                               if (unlikely(!cb))
+                                       goto reject;
+                               if (unlikely(++p_ptr->publ.conn_unacked >= 
+                                            TIPC_FLOW_CONTROL_WIN))
+                                       tipc_acknowledge(dref, 
+                                                        p_ptr->publ.conn_unacked);
+                               skb_pull(buf, msg_hdr_sz(msg));
+                               cb(usr_handle, dref, &buf, msg_data(msg),
+                                  msg_data_sz(msg));
+                               break;
+                       }
+               case TIPC_DIRECT_MSG:{
+                               tipc_msg_event cb = up_ptr->msg_cb;
+
+                               spin_unlock_bh(p_ptr->publ.lock);
+                               if (unlikely(connected))
+                                       goto reject;
+                               if (unlikely(!cb))
+                                       goto reject;
+                               skb_pull(buf, msg_hdr_sz(msg));
+                               cb(usr_handle, dref, &buf, msg_data(msg), 
+                                  msg_data_sz(msg), msg_importance(msg),
+                                  &orig);
+                               break;
+                       }
+               case TIPC_NAMED_MSG:{
+                               tipc_named_msg_event cb = up_ptr->named_msg_cb;
+
+                               spin_unlock_bh(p_ptr->publ.lock);
+                               if (unlikely(connected))
+                                       goto reject;
+                               if (unlikely(!cb))
+                                       goto reject;
+                               if (unlikely(!published))
+                                       goto reject;
+                               dseq.type =  msg_nametype(msg);
+                               dseq.lower = msg_nameinst(msg);
+                               dseq.upper = dseq.lower;
+                               skb_pull(buf, msg_hdr_sz(msg));
+                               cb(usr_handle, dref, &buf, msg_data(msg), 
+                                  msg_data_sz(msg), msg_importance(msg),
+                                  &orig, &dseq);
+                               break;
+                       }
+               }
+               if (buf)
+                       buf_discard(buf);
+               buf = next;
+               continue;
+err:
+               switch (msg_type(msg)) {
+               
+               case TIPC_CONN_MSG:{
+                               tipc_conn_shutdown_event cb = 
+                                       up_ptr->conn_err_cb;
+                               u32 peer_port = port_peerport(p_ptr);
+                               u32 peer_node = port_peernode(p_ptr);
+
+                               spin_unlock_bh(p_ptr->publ.lock);
+                               if (!connected || !cb)
+                                       break;
+                               if (msg_origport(msg) != peer_port)
+                                       break;
+                               if (msg_orignode(msg) != peer_node)
+                                       break;
+                               tipc_disconnect(dref);
+                               skb_pull(buf, msg_hdr_sz(msg));
+                               cb(usr_handle, dref, &buf, msg_data(msg),
+                                  msg_data_sz(msg), msg_errcode(msg));
+                               break;
+                       }
+               case TIPC_DIRECT_MSG:{
+                               tipc_msg_err_event cb = up_ptr->err_cb;
+
+                               spin_unlock_bh(p_ptr->publ.lock);
+                               if (connected || !cb)
+                                       break;
+                               skb_pull(buf, msg_hdr_sz(msg));
+                               cb(usr_handle, dref, &buf, msg_data(msg),
+                                  msg_data_sz(msg), msg_errcode(msg), &orig);
+                               break;
+                       }
+               case TIPC_NAMED_MSG:{
+                               tipc_named_msg_err_event cb = 
+                                       up_ptr->named_err_cb;
+
+                               spin_unlock_bh(p_ptr->publ.lock);
+                               if (connected || !cb)
+                                       break;
+                               dseq.type =  msg_nametype(msg);
+                               dseq.lower = msg_nameinst(msg);
+                               dseq.upper = dseq.lower;
+                               skb_pull(buf, msg_hdr_sz(msg));
+                               cb(usr_handle, dref, &buf, msg_data(msg), 
+                                  msg_data_sz(msg), msg_errcode(msg), &dseq);
+                               break;
+                       }
+               }
+               if (buf)
+                       buf_discard(buf);
+               buf = next;
+               continue;
+reject:
+               tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+               buf = next;
+       }
+}
+
+/*
+ *  port_dispatcher(): Dispatcher for messages destinated
+ *  to the tipc_port interface. Called with port locked.
+ */
+
+static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf)
+{
+       buf->next = NULL;
+       spin_lock_bh(&queue_lock);
+       if (msg_queue_head) {
+               msg_queue_tail->next = buf;
+               msg_queue_tail = buf;
+       } else {
+               msg_queue_tail = msg_queue_head = buf;
+               k_signal((Handler)port_dispatcher_sigh, 0);
+       }
+       spin_unlock_bh(&queue_lock);
+       return TIPC_OK;
+}
+
+/* 
+ * Wake up port after congestion: Called with port locked,
+ *                                
+ */
+
+static void port_wakeup_sh(unsigned long ref)
+{
+       struct port *p_ptr;
+       struct user_port *up_ptr;
+       tipc_continue_event cb = 0;
+       void *uh = 0;
+
+       p_ptr = port_lock(ref);
+       if (p_ptr) {
+               up_ptr = p_ptr->user_port;
+               if (up_ptr) {
+                       cb = up_ptr->continue_event_cb;
+                       uh = up_ptr->usr_handle;
+               }
+               port_unlock(p_ptr);
+       }
+       if (cb)
+               cb(uh, ref);
+}
+
+
+static void port_wakeup(struct tipc_port *p_ptr)
+{
+       k_signal((Handler)port_wakeup_sh, p_ptr->ref);
+}
+
+void tipc_acknowledge(u32 ref, u32 ack)
+{
+       struct port *p_ptr;
+       struct sk_buff *buf = 0;
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return;
+       if (p_ptr->publ.connected) {
+               p_ptr->publ.conn_unacked -= ack;
+               buf = port_build_proto_msg(port_peerport(p_ptr),
+                                          port_peernode(p_ptr),
+                                          ref,
+                                          tipc_own_addr,
+                                          CONN_MANAGER,
+                                          CONN_ACK,
+                                          TIPC_OK, 
+                                          port_out_seqno(p_ptr),
+                                          ack);
+       }
+       port_unlock(p_ptr);
+       net_route_msg(buf);
+}
+
+/*
+ * tipc_createport(): user level call. Will add port to
+ *                    registry if non-zero user_ref.
+ */
+
+int tipc_createport(u32 user_ref, 
+                   void *usr_handle, 
+                   unsigned int importance, 
+                   tipc_msg_err_event error_cb, 
+                   tipc_named_msg_err_event named_error_cb, 
+                   tipc_conn_shutdown_event conn_error_cb, 
+                   tipc_msg_event msg_cb, 
+                   tipc_named_msg_event named_msg_cb, 
+                   tipc_conn_msg_event conn_msg_cb, 
+                   tipc_continue_event continue_event_cb,/* May be zero */
+                   u32 *portref)
+{
+       struct user_port *up_ptr;
+       struct port *p_ptr; 
+       u32 ref;
+
+       up_ptr = (struct user_port *)kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
+       if (up_ptr == NULL) {
+               return -ENOMEM;
+       }
+       ref = tipc_createport_raw(0, port_dispatcher, port_wakeup, importance);
+       p_ptr = port_lock(ref);
+       if (!p_ptr) {
+               kfree(up_ptr);
+               return -ENOMEM;
+       }
+
+       p_ptr->user_port = up_ptr;
+       up_ptr->user_ref = user_ref;
+       up_ptr->usr_handle = usr_handle;
+       up_ptr->ref = p_ptr->publ.ref;
+       up_ptr->err_cb = error_cb;
+       up_ptr->named_err_cb = named_error_cb;
+       up_ptr->conn_err_cb = conn_error_cb;
+       up_ptr->msg_cb = msg_cb;
+       up_ptr->named_msg_cb = named_msg_cb;
+       up_ptr->conn_msg_cb = conn_msg_cb;
+       up_ptr->continue_event_cb = continue_event_cb;
+       INIT_LIST_HEAD(&up_ptr->uport_list);
+       reg_add_port(up_ptr);
+       *portref = p_ptr->publ.ref;
+       dbg(" tipc_createport: %x with ref %u\n", p_ptr, p_ptr->publ.ref);        
+       port_unlock(p_ptr);
+       return TIPC_OK;
+}
+
+int tipc_ownidentity(u32 ref, struct tipc_portid *id)
+{
+       id->ref = ref;
+       id->node = tipc_own_addr;
+       return TIPC_OK;
+}
+
+int tipc_portimportance(u32 ref, unsigned int *importance)
+{
+       struct port *p_ptr;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       *importance = (unsigned int)msg_importance(&p_ptr->publ.phdr);
+       spin_unlock_bh(p_ptr->publ.lock);
+       return TIPC_OK;
+}
+
+int tipc_set_portimportance(u32 ref, unsigned int imp)
+{
+       struct port *p_ptr;
+
+       if (imp > TIPC_CRITICAL_IMPORTANCE)
+               return -EINVAL;
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       msg_set_importance(&p_ptr->publ.phdr, (u32)imp);
+       spin_unlock_bh(p_ptr->publ.lock);
+       return TIPC_OK;
+}
+
+
+int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
+{
+       struct port *p_ptr;
+       struct publication *publ;
+       u32 key;
+       int res = -EINVAL;
+
+       p_ptr = port_lock(ref);
+       dbg("tipc_publ %u, p_ptr = %x, conn = %x, scope = %x, "
+           "lower = %u, upper = %u\n",
+           ref, p_ptr, p_ptr->publ.connected, scope, seq->lower, seq->upper);
+       if (!p_ptr)
+               return -EINVAL;
+       if (p_ptr->publ.connected)
+               goto exit;
+       if (seq->lower > seq->upper)
+               goto exit;
+       if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE))
+               goto exit;
+       key = ref + p_ptr->pub_count + 1;
+       if (key == ref) {
+               res = -EADDRINUSE;
+               goto exit;
+       }
+       publ = nametbl_publish(seq->type, seq->lower, seq->upper,
+                              scope, p_ptr->publ.ref, key);
+       if (publ) {
+               list_add(&publ->pport_list, &p_ptr->publications);
+               p_ptr->pub_count++;
+               p_ptr->publ.published = 1;
+               res = TIPC_OK;
+       }
+exit:
+       port_unlock(p_ptr);
+       return res;
+}
+
+int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
+{
+       struct port *p_ptr;
+       struct publication *publ;
+       struct publication *tpubl;
+       int res = -EINVAL;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       if (!p_ptr->publ.published)
+               goto exit;
+       if (!seq) {
+               list_for_each_entry_safe(publ, tpubl, 
+                                        &p_ptr->publications, pport_list) {
+                       nametbl_withdraw(publ->type, publ->lower, 
+                                        publ->ref, publ->key);
+               }
+               res = TIPC_OK;
+       } else {
+               list_for_each_entry_safe(publ, tpubl, 
+                                        &p_ptr->publications, pport_list) {
+                       if (publ->scope != scope)
+                               continue;
+                       if (publ->type != seq->type)
+                               continue;
+                       if (publ->lower != seq->lower)
+                               continue;
+                       if (publ->upper != seq->upper)
+                               break;
+                       nametbl_withdraw(publ->type, publ->lower, 
+                                        publ->ref, publ->key);
+                       res = TIPC_OK;
+                       break;
+               }
+       }
+       if (list_empty(&p_ptr->publications))
+               p_ptr->publ.published = 0;
+exit:
+       port_unlock(p_ptr);
+       return res;
+}
+
+int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       int res = -EINVAL;
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       if (p_ptr->publ.published || p_ptr->publ.connected)
+               goto exit;
+       if (!peer->ref)
+               goto exit;
+
+       msg = &p_ptr->publ.phdr;
+       msg_set_destnode(msg, peer->node);
+       msg_set_destport(msg, peer->ref);
+       msg_set_orignode(msg, tipc_own_addr);
+       msg_set_origport(msg, p_ptr->publ.ref);
+       msg_set_transp_seqno(msg, 42);
+       msg_set_type(msg, TIPC_CONN_MSG);
+       if (!may_route(peer->node))
+               msg_set_hdr_sz(msg, SHORT_H_SIZE);
+       else
+               msg_set_hdr_sz(msg, LONG_H_SIZE);
+
+       p_ptr->probing_interval = PROBING_INTERVAL;
+       p_ptr->probing_state = CONFIRMED;
+       p_ptr->publ.connected = 1;
+       k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
+
+       nodesub_subscribe(&p_ptr->subscription,peer->node,
+                         (void *)(unsigned long)ref,
+                         (net_ev_handler)port_handle_node_down);
+       res = TIPC_OK;
+exit:
+       port_unlock(p_ptr);
+       p_ptr->max_pkt = link_get_max_pkt(peer->node, ref);
+       return res;
+}
+
+/*
+ * tipc_disconnect(): Disconnect port form peer.
+ *                    This is a node local operation.
+ */
+
+int tipc_disconnect(u32 ref)
+{
+       struct port *p_ptr;
+       int res = -ENOTCONN;
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       if (p_ptr->publ.connected) {
+               p_ptr->publ.connected = 0;
+               /* let timer expire on it's own to avoid deadlock! */
+               nodesub_unsubscribe(&p_ptr->subscription);
+               res = TIPC_OK;
+       }
+       port_unlock(p_ptr);
+       return res;
+}
+
+/*
+ * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
+ */
+int tipc_shutdown(u32 ref)
+{
+       struct port *p_ptr;
+       struct sk_buff *buf = 0;
+
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+
+       if (p_ptr->publ.connected) {
+               u32 imp = msg_importance(&p_ptr->publ.phdr);
+               if (imp < TIPC_CRITICAL_IMPORTANCE)
+                       imp++;
+               buf = port_build_proto_msg(port_peerport(p_ptr),
+                                          port_peernode(p_ptr),
+                                          ref,
+                                          tipc_own_addr,
+                                          imp,
+                                          TIPC_CONN_MSG,
+                                          TIPC_CONN_SHUTDOWN, 
+                                          port_out_seqno(p_ptr),
+                                          0);
+       }
+       port_unlock(p_ptr);
+       net_route_msg(buf);
+       return tipc_disconnect(ref);
+}
+
+int tipc_isconnected(u32 ref, int *isconnected)
+{
+       struct port *p_ptr;
+       
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       *isconnected = p_ptr->publ.connected;
+       port_unlock(p_ptr);
+       return TIPC_OK;
+}
+
+int tipc_peer(u32 ref, struct tipc_portid *peer)
+{
+       struct port *p_ptr;
+       int res;
+        
+       p_ptr = port_lock(ref);
+       if (!p_ptr)
+               return -EINVAL;
+       if (p_ptr->publ.connected) {
+               peer->ref = port_peerport(p_ptr);
+               peer->node = port_peernode(p_ptr);
+               res = TIPC_OK;
+       } else
+               res = -ENOTCONN;
+       port_unlock(p_ptr);
+       return res;
+}
+
+int tipc_ref_valid(u32 ref)
+{
+       /* Works irrespective of type */
+       return !!ref_deref(ref);
+}
+
+
+/*
+ *  port_recv_sections(): Concatenate and deliver sectioned
+ *                        message for this node.
+ */
+
+int port_recv_sections(struct port *sender, unsigned int num_sect,
+                      struct iovec const *msg_sect)
+{
+       struct sk_buff *buf;
+       int res;
+        
+       res = msg_build(&sender->publ.phdr, msg_sect, num_sect,
+                       MAX_MSG_SIZE, !sender->user_port, &buf);
+       if (likely(buf))
+               port_recv_msg(buf);
+       return res;
+}
+
+/**
+ * tipc_send - send message sections on connection
+ */
+
+int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
+{
+       struct port *p_ptr;
+       u32 destnode;
+       int res;
+
+       p_ptr = port_deref(ref);
+       if (!p_ptr || !p_ptr->publ.connected)
+               return -EINVAL;
+
+       p_ptr->publ.congested = 1;
+       if (!port_congested(p_ptr)) {
+               destnode = port_peernode(p_ptr);
+               if (likely(destnode != tipc_own_addr))
+                       res = link_send_sections_fast(p_ptr, msg_sect, num_sect,
+                                                     destnode);
+               else
+                       res = port_recv_sections(p_ptr, num_sect, msg_sect);
+
+               if (likely(res != -ELINKCONG)) {
+                       port_incr_out_seqno(p_ptr);
+                       p_ptr->publ.congested = 0;
+                       p_ptr->sent++;
+                       return res;
+               }
+       }
+       if (port_unreliable(p_ptr)) {
+               p_ptr->publ.congested = 0;
+               /* Just calculate msg length and return */
+               return msg_calc_data_size(msg_sect, num_sect);
+       }
+       return -ELINKCONG;
+}
+
+/** 
+ * tipc_send_buf - send message buffer on connection
+ */
+
+int tipc_send_buf(u32 ref, struct sk_buff *buf, unsigned int dsz)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       u32 destnode;
+       u32 hsz;
+       u32 sz;
+       u32 res;
+        
+       p_ptr = port_deref(ref);
+       if (!p_ptr || !p_ptr->publ.connected)
+               return -EINVAL;
+
+       msg = &p_ptr->publ.phdr;
+       hsz = msg_hdr_sz(msg);
+       sz = hsz + dsz;
+       msg_set_size(msg, sz);
+       if (skb_cow(buf, hsz))
+               return -ENOMEM;
+
+       skb_push(buf, hsz);
+       memcpy(buf->data, (unchar *)msg, hsz);
+       destnode = msg_destnode(msg);
+       p_ptr->publ.congested = 1;
+       if (!port_congested(p_ptr)) {
+               if (likely(destnode != tipc_own_addr))
+                       res = tipc_send_buf_fast(buf, destnode);
+               else {
+                       port_recv_msg(buf);
+                       res = sz;
+               }
+               if (likely(res != -ELINKCONG)) {
+                       port_incr_out_seqno(p_ptr);
+                       p_ptr->sent++;
+                       p_ptr->publ.congested = 0;
+                       return res;
+               }
+       }
+       if (port_unreliable(p_ptr)) {
+               p_ptr->publ.congested = 0;
+               return dsz;
+       }
+       return -ELINKCONG;
+}
+
+/**
+ * tipc_forward2name - forward message sections to port name
+ */
+
+int tipc_forward2name(u32 ref, 
+                     struct tipc_name const *name, 
+                     u32 domain,
+                     u32 num_sect, 
+                     struct iovec const *msg_sect,
+                     struct tipc_portid const *orig, 
+                     unsigned int importance)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       u32 destnode = domain;
+       u32 destport = 0;
+       int res;
+
+       p_ptr = port_deref(ref);
+       if (!p_ptr || p_ptr->publ.connected)
+               return -EINVAL;
+
+       msg = &p_ptr->publ.phdr;
+       msg_set_type(msg, TIPC_NAMED_MSG);
+       msg_set_orignode(msg, orig->node);
+       msg_set_origport(msg, orig->ref);
+       msg_set_hdr_sz(msg, LONG_H_SIZE);
+       msg_set_nametype(msg, name->type);
+       msg_set_nameinst(msg, name->instance);
+       msg_set_lookup_scope(msg, addr_scope(domain));
+       if (importance <= TIPC_CRITICAL_IMPORTANCE)
+               msg_set_importance(msg,importance);
+       destport = nametbl_translate(name->type, name->instance, &destnode);
+       msg_set_destnode(msg, destnode);
+       msg_set_destport(msg, destport);
+
+       if (likely(destport || destnode)) {
+               p_ptr->sent++;
+               if (likely(destnode == tipc_own_addr))
+                       return port_recv_sections(p_ptr, num_sect, msg_sect);
+               res = link_send_sections_fast(p_ptr, msg_sect, num_sect, 
+                                             destnode);
+               if (likely(res != -ELINKCONG))
+                       return res;
+               if (port_unreliable(p_ptr)) {
+                       /* Just calculate msg length and return */
+                       return msg_calc_data_size(msg_sect, num_sect);
+               }
+               return -ELINKCONG;
+       }
+       return port_reject_sections(p_ptr, msg, msg_sect, num_sect, 
+                                   TIPC_ERR_NO_NAME);
+}
+
+/**
+ * tipc_send2name - send message sections to port name
+ */
+
+int tipc_send2name(u32 ref, 
+                  struct tipc_name const *name,
+                  unsigned int domain, 
+                  unsigned int num_sect, 
+                  struct iovec const *msg_sect)
+{
+       struct tipc_portid orig;
+
+       orig.ref = ref;
+       orig.node = tipc_own_addr;
+       return tipc_forward2name(ref, name, domain, num_sect, msg_sect, &orig,
+                                TIPC_PORT_IMPORTANCE);
+}
+
+/** 
+ * tipc_forward_buf2name - forward message buffer to port name
+ */
+
+int tipc_forward_buf2name(u32 ref,
+                         struct tipc_name const *name,
+                         u32 domain,
+                         struct sk_buff *buf,
+                         unsigned int dsz,
+                         struct tipc_portid const *orig,
+                         unsigned int importance)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       u32 destnode = domain;
+       u32 destport = 0;
+       int res;
+
+       p_ptr = (struct port *)ref_deref(ref);
+       if (!p_ptr || p_ptr->publ.connected)
+               return -EINVAL;
+
+       msg = &p_ptr->publ.phdr;
+       if (importance <= TIPC_CRITICAL_IMPORTANCE)
+               msg_set_importance(msg, importance);
+       msg_set_type(msg, TIPC_NAMED_MSG);
+       msg_set_orignode(msg, orig->node);
+       msg_set_origport(msg, orig->ref);
+       msg_set_nametype(msg, name->type);
+       msg_set_nameinst(msg, name->instance);
+       msg_set_lookup_scope(msg, addr_scope(domain));
+       msg_set_hdr_sz(msg, LONG_H_SIZE);
+       msg_set_size(msg, LONG_H_SIZE + dsz);
+       destport = nametbl_translate(name->type, name->instance, &destnode);
+       msg_set_destnode(msg, destnode);
+       msg_set_destport(msg, destport);
+       msg_dbg(msg, "forw2name ==> ");
+       if (skb_cow(buf, LONG_H_SIZE))
+               return -ENOMEM;
+       skb_push(buf, LONG_H_SIZE);
+       memcpy(buf->data, (unchar *)msg, LONG_H_SIZE);
+       msg_dbg(buf_msg(buf),"PREP:");
+       if (likely(destport || destnode)) {
+               p_ptr->sent++;
+               if (destnode == tipc_own_addr)
+                       return port_recv_msg(buf);
+               res = tipc_send_buf_fast(buf, destnode);
+               if (likely(res != -ELINKCONG))
+                       return res;
+               if (port_unreliable(p_ptr))
+                       return dsz;
+               return -ELINKCONG;
+       }
+       return tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
+}
+
+/** 
+ * tipc_send_buf2name - send message buffer to port name
+ */
+
+int tipc_send_buf2name(u32 ref, 
+                      struct tipc_name const *dest, 
+                      u32 domain,
+                      struct sk_buff *buf, 
+                      unsigned int dsz)
+{
+       struct tipc_portid orig;
+
+       orig.ref = ref;
+       orig.node = tipc_own_addr;
+       return tipc_forward_buf2name(ref, dest, domain, buf, dsz, &orig,
+                                    TIPC_PORT_IMPORTANCE);
+}
+
+/** 
+ * tipc_forward2port - forward message sections to port identity
+ */
+
+int tipc_forward2port(u32 ref,
+                     struct tipc_portid const *dest,
+                     unsigned int num_sect, 
+                     struct iovec const *msg_sect,
+                     struct tipc_portid const *orig, 
+                     unsigned int importance)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       int res;
+
+       p_ptr = port_deref(ref);
+       if (!p_ptr || p_ptr->publ.connected)
+               return -EINVAL;
+
+       msg = &p_ptr->publ.phdr;
+       msg_set_type(msg, TIPC_DIRECT_MSG);
+       msg_set_orignode(msg, orig->node);
+       msg_set_origport(msg, orig->ref);
+       msg_set_destnode(msg, dest->node);
+       msg_set_destport(msg, dest->ref);
+       msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
+       if (importance <= TIPC_CRITICAL_IMPORTANCE)
+               msg_set_importance(msg, importance);
+       p_ptr->sent++;
+       if (dest->node == tipc_own_addr)
+               return port_recv_sections(p_ptr, num_sect, msg_sect);
+       res = link_send_sections_fast(p_ptr, msg_sect, num_sect, dest->node);
+       if (likely(res != -ELINKCONG))
+               return res;
+       if (port_unreliable(p_ptr)) {
+               /* Just calculate msg length and return */
+               return msg_calc_data_size(msg_sect, num_sect);
+       }
+       return -ELINKCONG;
+}
+
+/** 
+ * tipc_send2port - send message sections to port identity 
+ */
+
+int tipc_send2port(u32 ref, 
+                  struct tipc_portid const *dest,
+                  unsigned int num_sect, 
+                  struct iovec const *msg_sect)
+{
+       struct tipc_portid orig;
+
+       orig.ref = ref;
+       orig.node = tipc_own_addr;
+       return tipc_forward2port(ref, dest, num_sect, msg_sect, &orig, 
+                                TIPC_PORT_IMPORTANCE);
+}
+
+/** 
+ * tipc_forward_buf2port - forward message buffer to port identity
+ */
+int tipc_forward_buf2port(u32 ref,
+                         struct tipc_portid const *dest,
+                         struct sk_buff *buf,
+                         unsigned int dsz,
+                         struct tipc_portid const *orig,
+                         unsigned int importance)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg;
+       int res;
+
+       p_ptr = (struct port *)ref_deref(ref);
+       if (!p_ptr || p_ptr->publ.connected)
+               return -EINVAL;
+
+       msg = &p_ptr->publ.phdr;
+       msg_set_type(msg, TIPC_DIRECT_MSG);
+       msg_set_orignode(msg, orig->node);
+       msg_set_origport(msg, orig->ref);
+       msg_set_destnode(msg, dest->node);
+       msg_set_destport(msg, dest->ref);
+       msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
+       if (importance <= TIPC_CRITICAL_IMPORTANCE)
+               msg_set_importance(msg, importance);
+       msg_set_size(msg, DIR_MSG_H_SIZE + dsz);
+       if (skb_cow(buf, DIR_MSG_H_SIZE))
+               return -ENOMEM;
+
+       skb_push(buf, DIR_MSG_H_SIZE);
+       memcpy(buf->data, (unchar *)msg, DIR_MSG_H_SIZE);
+       msg_dbg(msg, "buf2port: ");
+       p_ptr->sent++;
+       if (dest->node == tipc_own_addr)
+               return port_recv_msg(buf);
+       res = tipc_send_buf_fast(buf, dest->node);
+       if (likely(res != -ELINKCONG))
+               return res;
+       if (port_unreliable(p_ptr))
+               return dsz;
+       return -ELINKCONG;
+}
+
+/** 
+ * tipc_send_buf2port - send message buffer to port identity
+ */
+
+int tipc_send_buf2port(u32 ref, 
+                      struct tipc_portid const *dest,
+                      struct sk_buff *buf, 
+                      unsigned int dsz)
+{
+       struct tipc_portid orig;
+
+       orig.ref = ref;
+       orig.node = tipc_own_addr;
+       return tipc_forward_buf2port(ref, dest, buf, dsz, &orig, 
+                                    TIPC_PORT_IMPORTANCE);
+}
+
diff --git a/net/tipc/port.h b/net/tipc/port.h
new file mode 100644 (file)
index 0000000..e829a99
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * net/tipc/port.h: Include file for TIPC port code
+ * 
+ * Copyright (c) 1994-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_PORT_H
+#define _TIPC_PORT_H
+
+#include <net/tipc/tipc_port.h>
+#include "ref.h"
+#include "net.h"
+#include "msg.h"
+#include "dbg.h"
+#include "node_subscr.h"
+
+/**
+ * struct user_port - TIPC user port (used with native API)
+ * @user_ref: id of user who created user port
+ * @usr_handle: user-specified field
+ * @ref: object reference to associated TIPC port
+ * <various callback routines>
+ * @uport_list: adjacent user ports in list of ports held by user
+ */
+struct user_port {
+       u32 user_ref;
+       void *usr_handle; 
+       u32 ref;
+       tipc_msg_err_event err_cb; 
+       tipc_named_msg_err_event named_err_cb; 
+       tipc_conn_shutdown_event conn_err_cb; 
+       tipc_msg_event msg_cb; 
+       tipc_named_msg_event named_msg_cb; 
+       tipc_conn_msg_event conn_msg_cb; 
+       tipc_continue_event continue_event_cb;
+       struct list_head uport_list;
+};
+
+/**
+ * struct port - TIPC port structure
+ * @publ: TIPC port info available to privileged users
+ * @port_list: adjacent ports in TIPC's global list of ports
+ * @dispatcher: ptr to routine which handles received messages
+ * @wakeup: ptr to routine to call when port is no longer congested
+ * @user_port: ptr to user port associated with port (if any)
+ * @wait_list: adjacent ports in list of ports waiting on link congestion
+ * @congested_link: ptr to congested link port is waiting on
+ * @waiting_pkts:
+ * @sent:
+ * @acked:
+ * @publications: list of publications for port
+ * @pub_count: total # of publications port has made during its lifetime
+ * @max_pkt: maximum packet size "hint" used when building messages sent by port
+ * @probing_state:
+ * @probing_interval:
+ * @last_in_seqno:
+ * @timer_ref:
+ * @subscription: "node down" subscription used to terminate failed connections
+ */
+
+struct port {
+       struct tipc_port publ;
+       struct list_head port_list;
+       u32 (*dispatcher)(struct tipc_port *, struct sk_buff *);
+       void (*wakeup)(struct tipc_port *);
+       struct user_port *user_port;
+       struct list_head wait_list;
+       struct link *congested_link;
+       u32 waiting_pkts;
+       u32 sent;
+       u32 acked;
+       struct list_head publications;
+       u32 pub_count;
+       u32 max_pkt;
+       u32 probing_state;
+       u32 probing_interval;
+       u32 last_in_seqno;
+       struct timer_list timer;
+       struct node_subscr subscription;
+};
+
+extern spinlock_t port_list_lock;
+struct port_list;
+
+int port_recv_sections(struct port *p_ptr, u32 num_sect, 
+                      struct iovec const *msg_sect);
+int port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
+                        struct iovec const *msg_sect, u32 num_sect,
+                        int err);
+struct sk_buff *port_get_ports(void);
+struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space);
+void port_recv_proto_msg(struct sk_buff *buf);
+void port_recv_mcast(struct sk_buff *buf, struct port_list *dp);
+void port_reinit(void);
+
+/**
+ * port_lock - lock port instance referred to and return its pointer
+ */
+
+static inline struct port *port_lock(u32 ref)
+{
+       return (struct port *)ref_lock(ref);
+}
+
+/** 
+ * port_unlock - unlock a port instance
+ * 
+ * Can use pointer instead of ref_unlock() since port is already locked.
+ */
+
+static inline void port_unlock(struct port *p_ptr)
+{
+       spin_unlock_bh(p_ptr->publ.lock);
+}
+
+static inline struct port* port_deref(u32 ref)
+{
+       return (struct port *)ref_deref(ref);
+}
+
+static inline u32 peer_port(struct port *p_ptr)
+{
+       return msg_destport(&p_ptr->publ.phdr);
+}
+
+static inline u32 peer_node(struct port *p_ptr)
+{
+       return msg_destnode(&p_ptr->publ.phdr);
+}
+
+static inline int port_congested(struct port *p_ptr)
+{
+       return((p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2));
+}
+
+/** 
+ * port_recv_msg - receive message from lower layer and deliver to port user
+ */
+
+static inline int port_recv_msg(struct sk_buff *buf)
+{
+       struct port *p_ptr;
+       struct tipc_msg *msg = buf_msg(buf);
+       u32 destport = msg_destport(msg);
+       u32 dsz = msg_data_sz(msg);
+       u32 err;
+       
+       /* forward unresolved named message */
+       if (unlikely(!destport)) {
+               net_route_msg(buf);
+               return dsz;
+       }
+
+       /* validate destination & pass to port, otherwise reject message */
+       p_ptr = port_lock(destport);
+       if (likely(p_ptr)) {
+               if (likely(p_ptr->publ.connected)) {
+                       if ((unlikely(msg_origport(msg) != peer_port(p_ptr))) ||
+                           (unlikely(msg_orignode(msg) != peer_node(p_ptr))) ||
+                           (unlikely(!msg_connected(msg)))) {
+                               err = TIPC_ERR_NO_PORT;
+                               port_unlock(p_ptr);
+                               goto reject;
+                       }
+               }
+               err = p_ptr->dispatcher(&p_ptr->publ, buf);
+               port_unlock(p_ptr);
+               if (likely(!err))
+                       return dsz;
+       } else {
+               err = TIPC_ERR_NO_PORT;
+       }
+reject:
+       dbg("port->rejecting, err = %x..\n",err);
+       return tipc_reject_msg(buf, err);
+}
+
+#endif
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
new file mode 100644 (file)
index 0000000..944093f
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * net/tipc/ref.c: TIPC object registry code
+ * 
+ * Copyright (c) 1991-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "ref.h"
+#include "port.h"
+#include "subscr.h"
+#include "name_distr.h"
+#include "name_table.h"
+#include "config.h"
+#include "discover.h"
+#include "bearer.h"
+#include "node.h"
+#include "bcast.h"
+
+/*
+ * Object reference table consists of 2**N entries.
+ *
+ * A used entry has object ptr != 0, reference == XXXX|own index
+ *                                  (XXXX changes each time entry is acquired) 
+ * A free entry has object ptr == 0, reference == YYYY|next free index
+ *                                  (YYYY is one more than last used XXXX)
+ *
+ * Free list is initially chained from entry (2**N)-1 to entry 1. 
+ * Entry 0 is not used to allow index 0 to indicate the end of the free list.
+ *
+ * Note: Any accidental reference of the form XXXX|0--0 won't match entry 0
+ * because entry 0's reference field has the form XXXX|1--1.
+ */
+
+struct ref_table ref_table = { 0 };
+
+rwlock_t reftbl_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * ref_table_init - create reference table for objects
+ */
+
+int ref_table_init(u32 requested_size, u32 start)
+{
+       struct reference *table;
+       u32 sz = 1 << 4;
+       u32 index_mask;
+       int i;
+
+       while (sz < requested_size) {
+               sz <<= 1;
+       }
+       table = (struct reference *)vmalloc(sz * sizeof(struct reference));
+       if (table == NULL)
+               return -ENOMEM;
+
+       write_lock_bh(&reftbl_lock);
+       index_mask = sz - 1;
+       for (i = sz - 1; i >= 0; i--) {
+               table[i].object = 0;
+               table[i].lock = SPIN_LOCK_UNLOCKED;
+               table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
+       }
+       ref_table.entries = table;
+       ref_table.index_mask = index_mask;
+       ref_table.first_free = sz - 1;
+       ref_table.last_free = 1;
+       write_unlock_bh(&reftbl_lock);
+       return TIPC_OK;
+}
+
+/**
+ * ref_table_stop - destroy reference table for objects
+ */
+
+void ref_table_stop(void)
+{
+       if (!ref_table.entries)
+               return;
+
+       vfree(ref_table.entries);
+       ref_table.entries = 0;
+}
+
+/**
+ * ref_acquire - create reference to an object
+ * 
+ * Return a unique reference value which can be translated back to the pointer
+ * 'object' at a later time.  Also, pass back a pointer to the lock protecting 
+ * the object, but without locking it.
+ */
+
+u32 ref_acquire(void *object, spinlock_t **lock)
+{
+       struct reference *entry;
+       u32 index;
+       u32 index_mask;
+       u32 next_plus_upper;
+       u32 reference = 0;
+
+       assert(ref_table.entries && object);
+
+       write_lock_bh(&reftbl_lock);
+       if (ref_table.first_free) {
+               index = ref_table.first_free;
+               entry = &(ref_table.entries[index]);
+               index_mask = ref_table.index_mask;
+               /* take lock in case a previous user of entry still holds it */ 
+               spin_lock_bh(&entry->lock);  
+               next_plus_upper = entry->data.next_plus_upper;
+               ref_table.first_free = next_plus_upper & index_mask;
+               reference = (next_plus_upper & ~index_mask) + index;
+               entry->data.reference = reference;
+               entry->object = object;
+                if (lock != 0)
+                        *lock = &entry->lock;
+               spin_unlock_bh(&entry->lock);
+       }
+       write_unlock_bh(&reftbl_lock);
+       return reference;
+}
+
+/**
+ * ref_discard - invalidate references to an object
+ * 
+ * Disallow future references to an object and free up the entry for re-use.
+ * Note: The entry's spin_lock may still be busy after discard
+ */
+
+void ref_discard(u32 ref)
+{
+       struct reference *entry;
+       u32 index; 
+       u32 index_mask;
+
+       assert(ref_table.entries);
+       assert(ref != 0);
+
+       write_lock_bh(&reftbl_lock);
+       index_mask = ref_table.index_mask;
+       index = ref & index_mask;
+       entry = &(ref_table.entries[index]);
+       assert(entry->object != 0);
+       assert(entry->data.reference == ref);
+
+       /* mark entry as unused */
+       entry->object = 0;
+       if (ref_table.first_free == 0)
+               ref_table.first_free = index;
+       else
+               /* next_plus_upper is always XXXX|0--0 for last free entry */
+               ref_table.entries[ref_table.last_free].data.next_plus_upper 
+                       |= index;
+       ref_table.last_free = index;
+
+       /* increment upper bits of entry to invalidate subsequent references */
+       entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1);
+       write_unlock_bh(&reftbl_lock);
+}
+
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
new file mode 100644 (file)
index 0000000..429cde5
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * net/tipc/ref.h: Include file for TIPC object registry code
+ * 
+ * Copyright (c) 1991-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_REF_H
+#define _TIPC_REF_H
+
+/**
+ * struct reference - TIPC object reference entry
+ * @object: pointer to object associated with reference entry
+ * @lock: spinlock controlling access to object
+ * @data: reference value associated with object (or link to next unused entry)
+ */
+struct reference {
+       void *object;
+       spinlock_t lock;
+       union {
+               u32 next_plus_upper;
+               u32 reference;
+       } data;
+};
+
+/**
+ * struct ref_table - table of TIPC object reference entries
+ * @entries: pointer to array of reference entries
+ * @index_mask: bitmask for array index portion of reference values
+ * @first_free: array index of first unused object reference entry
+ * @last_free: array index of last unused object reference entry
+ */
+
+struct ref_table {
+       struct reference *entries;
+       u32 index_mask;
+       u32 first_free;
+       u32 last_free;
+};
+
+extern struct ref_table ref_table;
+
+int ref_table_init(u32 requested_size, u32 start);
+void ref_table_stop(void);
+
+u32 ref_acquire(void *object, spinlock_t **lock);
+void ref_discard(u32 ref);
+
+
+/**
+ * ref_lock - lock referenced object and return pointer to it
+ */
+
+static inline void *ref_lock(u32 ref)
+{
+       if (likely(ref_table.entries)) {
+               struct reference *r =
+                       &ref_table.entries[ref & ref_table.index_mask];
+
+               spin_lock_bh(&r->lock);
+               if (likely(r->data.reference == ref))
+                       return r->object;
+               spin_unlock_bh(&r->lock);
+       }
+       return 0;
+}
+
+/**
+ * ref_unlock - unlock referenced object 
+ */
+
+static inline void ref_unlock(u32 ref)
+{
+       if (likely(ref_table.entries)) {
+               struct reference *r =
+                       &ref_table.entries[ref & ref_table.index_mask];
+
+               if (likely(r->data.reference == ref))
+                       spin_unlock_bh(&r->lock);
+               else
+                       err("ref_unlock() invoked using obsolete reference\n");
+       }
+}
+
+/**
+ * ref_deref - return pointer referenced object (without locking it)
+ */
+
+static inline void *ref_deref(u32 ref)
+{
+       if (likely(ref_table.entries)) {
+               struct reference *r = 
+                       &ref_table.entries[ref & ref_table.index_mask];
+
+               if (likely(r->data.reference == ref))
+                       return r->object;
+       }
+       return 0;
+}
+
+#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
new file mode 100644 (file)
index 0000000..d21f8c0
--- /dev/null
@@ -0,0 +1,1726 @@
+/*
+ * net/tipc/socket.c: TIPC socket API
+ * 
+ * Copyright (c) 2001-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/socket.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <linux/fcntl.h>
+#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <asm/string.h>
+#include <asm/atomic.h>
+#include <net/sock.h>
+
+#include <linux/tipc.h>
+#include <linux/tipc_config.h>
+#include <net/tipc/tipc_msg.h>
+#include <net/tipc/tipc_port.h>
+
+#include "core.h"
+
+#define SS_LISTENING   -1      /* socket is listening */
+#define SS_READY       -2      /* socket is connectionless */
+
+#define OVERLOAD_LIMIT_BASE    5000
+
+struct tipc_sock {
+       struct sock sk;
+       struct tipc_port *p;
+       struct semaphore sem;
+};
+
+#define tipc_sk(sk) ((struct tipc_sock*)sk)
+
+static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
+static void wakeupdispatch(struct tipc_port *tport);
+
+static struct proto_ops packet_ops;
+static struct proto_ops stream_ops;
+static struct proto_ops msg_ops;
+
+static struct proto tipc_proto;
+
+static int sockets_enabled = 0;
+
+static atomic_t tipc_queue_size = ATOMIC_INIT(0);
+
+
+/* 
+ * sock_lock(): Lock a port/socket pair. lock_sock() can 
+ * not be used here, since the same lock must protect ports 
+ * with non-socket interfaces.
+ * See net.c for description of locking policy.
+ */
+static inline void sock_lock(struct tipc_sock* tsock)
+{
+        spin_lock_bh(tsock->p->lock);       
+}
+
+/* 
+ * sock_unlock(): Unlock a port/socket pair
+ */
+static inline void sock_unlock(struct tipc_sock* tsock)
+{
+        spin_unlock_bh(tsock->p->lock);
+}
+
+/**
+ * pollmask - determine the current set of poll() events for a socket
+ * @sock: socket structure
+ * 
+ * TIPC sets the returned events as follows:
+ * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
+ *    or if a connection-oriented socket is does not have an active connection
+ *    (i.e. a read operation will not block).
+ * b) POLLOUT is set except when a socket's connection has been terminated
+ *    (i.e. a write operation will not block).
+ * c) POLLHUP is set when a socket's connection has been terminated.
+ *
+ * IMPORTANT: The fact that a read or write operation will not block does NOT
+ * imply that the operation will succeed!
+ * 
+ * Returns pollmask value
+ */
+
+static inline u32 pollmask(struct socket *sock)
+{
+       u32 mask;
+
+       if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) ||
+           (sock->state == SS_UNCONNECTED) ||
+           (sock->state == SS_DISCONNECTING))
+               mask = (POLLRDNORM | POLLIN);
+       else
+               mask = 0;
+
+       if (sock->state == SS_DISCONNECTING) 
+               mask |= POLLHUP;
+       else
+               mask |= POLLOUT;
+
+       return mask;
+}
+
+
+/**
+ * advance_queue - discard first buffer in queue
+ * @tsock: TIPC socket
+ */
+
+static inline void advance_queue(struct tipc_sock *tsock)
+{
+        sock_lock(tsock);
+       buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue));
+        sock_unlock(tsock);
+       atomic_dec(&tipc_queue_size);
+}
+
+/**
+ * tipc_create - create a TIPC socket
+ * @sock: pre-allocated socket structure
+ * @protocol: protocol indicator (must be 0)
+ * 
+ * This routine creates and attaches a 'struct sock' to the 'struct socket',
+ * then create and attaches a TIPC port to the 'struct sock' part.
+ *
+ * Returns 0 on success, errno otherwise
+ */
+static int tipc_create(struct socket *sock, int protocol)
+{
+       struct tipc_sock *tsock;
+       struct tipc_port *port;
+       struct sock *sk;
+        u32 ref;
+
+       if ((sock->type != SOCK_STREAM) && 
+           (sock->type != SOCK_SEQPACKET) &&
+           (sock->type != SOCK_DGRAM) &&
+           (sock->type != SOCK_RDM))
+               return -EPROTOTYPE;
+
+       if (unlikely(protocol != 0))
+               return -EPROTONOSUPPORT;
+
+       ref = tipc_createport_raw(0, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE);
+       if (unlikely(!ref))
+               return -ENOMEM;
+
+       sock->state = SS_UNCONNECTED;
+
+       switch (sock->type) {
+       case SOCK_STREAM:
+               sock->ops = &stream_ops;
+               break;
+       case SOCK_SEQPACKET:
+               sock->ops = &packet_ops;
+               break;
+       case SOCK_DGRAM:
+               tipc_set_portunreliable(ref, 1);
+               /* fall through */
+       case SOCK_RDM:
+               tipc_set_portunreturnable(ref, 1);
+               sock->ops = &msg_ops;
+               sock->state = SS_READY;
+               break;
+       }
+
+       sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1);
+       if (!sk) {
+               tipc_deleteport(ref);
+               return -ENOMEM;
+       }
+
+       sock_init_data(sock, sk);
+       init_waitqueue_head(sk->sk_sleep);
+       sk->sk_rcvtimeo = 8 * HZ;   /* default connect timeout = 8s */
+
+       tsock = tipc_sk(sk);
+       port = tipc_get_port(ref);
+
+       tsock->p = port;
+       port->usr_handle = tsock;
+
+       init_MUTEX(&tsock->sem);
+
+       dbg("sock_create: %x\n",tsock);
+
+       atomic_inc(&tipc_user_count);
+
+       return 0;
+}
+
+/**
+ * release - destroy a TIPC socket
+ * @sock: socket to destroy
+ *
+ * This routine cleans up any messages that are still queued on the socket.
+ * For DGRAM and RDM socket types, all queued messages are rejected.
+ * For SEQPACKET and STREAM socket types, the first message is rejected
+ * and any others are discarded.  (If the first message on a STREAM socket
+ * is partially-read, it is discarded and the next one is rejected instead.)
+ * 
+ * NOTE: Rejected messages are not necessarily returned to the sender!  They
+ * are returned or discarded according to the "destination droppable" setting
+ * specified for the message by the sender.
+ *
+ * Returns 0 on success, errno otherwise
+ */
+
+static int release(struct socket *sock)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct sock *sk = sock->sk;
+       int res = TIPC_OK;
+       struct sk_buff *buf;
+
+        dbg("sock_delete: %x\n",tsock);
+       if (!tsock)
+               return 0;
+       down_interruptible(&tsock->sem);
+       if (!sock->sk) {
+               up(&tsock->sem);
+               return 0;
+       }
+       
+       /* Reject unreceived messages, unless no longer connected */
+
+       while (sock->state != SS_DISCONNECTING) {
+               sock_lock(tsock);
+               buf = skb_dequeue(&sk->sk_receive_queue);
+               if (!buf)
+                       tsock->p->usr_handle = 0;
+               sock_unlock(tsock);
+               if (!buf)
+                       break;
+               if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf)))
+                       buf_discard(buf);
+               else
+                       tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+               atomic_dec(&tipc_queue_size);
+       }
+
+       /* Delete TIPC port */
+
+       res = tipc_deleteport(tsock->p->ref);
+       sock->sk = NULL;
+
+       /* Discard any remaining messages */
+
+       while ((buf = skb_dequeue(&sk->sk_receive_queue))) {
+               buf_discard(buf);
+               atomic_dec(&tipc_queue_size);
+       }
+
+       up(&tsock->sem);
+
+       sock_put(sk);
+
+        atomic_dec(&tipc_user_count);
+       return res;
+}
+
+/**
+ * bind - associate or disassocate TIPC name(s) with a socket
+ * @sock: socket structure
+ * @uaddr: socket address describing name(s) and desired operation
+ * @uaddr_len: size of socket address data structure
+ * 
+ * Name and name sequence binding is indicated using a positive scope value;
+ * a negative scope value unbinds the specified name.  Specifying no name
+ * (i.e. a socket address length of 0) unbinds all names from the socket.
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
+       int res;
+
+       if (down_interruptible(&tsock->sem))
+               return -ERESTARTSYS;
+       
+       if (unlikely(!uaddr_len)) {
+               res = tipc_withdraw(tsock->p->ref, 0, 0);
+               goto exit;
+       }
+
+       if (uaddr_len < sizeof(struct sockaddr_tipc)) {
+               res = -EINVAL;
+               goto exit;
+       }
+
+       if (addr->family != AF_TIPC) {
+               res = -EAFNOSUPPORT;
+               goto exit;
+       }
+       if (addr->addrtype == TIPC_ADDR_NAME)
+               addr->addr.nameseq.upper = addr->addr.nameseq.lower;
+       else if (addr->addrtype != TIPC_ADDR_NAMESEQ) {
+               res = -EAFNOSUPPORT;
+               goto exit;
+       }
+        
+               if (addr->scope > 0)
+               res = tipc_publish(tsock->p->ref, addr->scope,
+                                  &addr->addr.nameseq);
+       else
+               res = tipc_withdraw(tsock->p->ref, -addr->scope,
+                                   &addr->addr.nameseq);
+exit:
+       up(&tsock->sem);
+       return res;
+}
+
+/** 
+ * get_name - get port ID of socket or peer socket
+ * @sock: socket structure
+ * @uaddr: area for returned socket address
+ * @uaddr_len: area for returned length of socket address
+ * @peer: 0 to obtain socket name, 1 to obtain peer socket name
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int get_name(struct socket *sock, struct sockaddr *uaddr, 
+                   int *uaddr_len, int peer)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
+       u32 res;
+
+       if (down_interruptible(&tsock->sem))
+               return -ERESTARTSYS;
+
+       *uaddr_len = sizeof(*addr);
+       addr->addrtype = TIPC_ADDR_ID;
+       addr->family = AF_TIPC;
+       addr->scope = 0;
+       if (peer)
+               res = tipc_peer(tsock->p->ref, &addr->addr.id);
+       else
+               res = tipc_ownidentity(tsock->p->ref, &addr->addr.id);
+       addr->addr.name.domain = 0;
+
+       up(&tsock->sem);
+       return res;
+}
+
+/**
+ * poll - read and possibly block on pollmask
+ * @file: file structure associated with the socket
+ * @sock: socket for which to calculate the poll bits
+ * @wait: ???
+ *
+ * Returns the pollmask
+ */
+
+static unsigned int poll(struct file *file, struct socket *sock, 
+                        poll_table *wait)
+{
+       poll_wait(file, sock->sk->sk_sleep, wait);
+       /* NEED LOCK HERE? */
+       return pollmask(sock);
+}
+
+/** 
+ * dest_name_check - verify user is permitted to send to specified port name
+ * @dest: destination address
+ * @m: descriptor for message to be sent
+ * 
+ * Prevents restricted configuration commands from being issued by
+ * unauthorized users.
+ * 
+ * Returns 0 if permission is granted, otherwise errno
+ */
+
+static inline int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
+{
+       struct tipc_cfg_msg_hdr hdr;
+
+        if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES))
+                return 0;
+        if (likely(dest->addr.name.name.type == TIPC_TOP_SRV))
+                return 0;
+
+        if (likely(dest->addr.name.name.type != TIPC_CFG_SRV))
+                return -EACCES;
+
+        if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))
+               return -EFAULT;
+       if ((ntohs(hdr.tcm_type) & 0xC000) & (!capable(CAP_NET_ADMIN)))
+               return -EACCES;
+        
+       return 0;
+}
+
+/**
+ * send_msg - send message in connectionless manner
+ * @iocb: (unused)
+ * @sock: socket structure
+ * @m: message to send
+ * @total_len: (unused)
+ * 
+ * Message must have an destination specified explicitly.
+ * Used for SOCK_RDM and SOCK_DGRAM messages, 
+ * and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections.
+ * (Note: 'SYN+' is prohibited on SOCK_STREAM.)
+ * 
+ * Returns the number of bytes sent on success, or errno otherwise
+ */
+
+static int send_msg(struct kiocb *iocb, struct socket *sock,
+                   struct msghdr *m, size_t total_len)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+        struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
+       struct sk_buff *buf;
+       int needs_conn;
+       int res = -EINVAL;
+
+       if (unlikely(!dest))
+               return -EDESTADDRREQ;
+       if (unlikely(dest->family != AF_TIPC))
+               return -EINVAL;
+
+       needs_conn = (sock->state != SS_READY);
+       if (unlikely(needs_conn)) {
+               if (sock->state == SS_LISTENING)
+                       return -EPIPE;
+               if (sock->state != SS_UNCONNECTED)
+                       return -EISCONN;
+               if ((tsock->p->published) ||
+                   ((sock->type == SOCK_STREAM) && (total_len != 0)))
+                       return -EOPNOTSUPP;
+       }
+
+       if (down_interruptible(&tsock->sem))
+               return -ERESTARTSYS;
+
+       if (needs_conn) {
+
+               /* Abort any pending connection attempts (very unlikely) */
+
+               while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
+                       tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
+                       atomic_dec(&tipc_queue_size);
+               }
+
+               sock->state = SS_CONNECTING;
+       }
+
+        do {
+                if (dest->addrtype == TIPC_ADDR_NAME) {
+                        if ((res = dest_name_check(dest, m)))
+                                goto exit;
+                        res = tipc_send2name(tsock->p->ref,
+                                             &dest->addr.name.name,
+                                             dest->addr.name.domain, 
+                                             m->msg_iovlen,
+                                             m->msg_iov);
+                }
+                else if (dest->addrtype == TIPC_ADDR_ID) {
+                        res = tipc_send2port(tsock->p->ref,
+                                             &dest->addr.id,
+                                             m->msg_iovlen,
+                                             m->msg_iov);
+                }
+                else if (dest->addrtype == TIPC_ADDR_MCAST) {
+                       if (needs_conn) {
+                               res = -EOPNOTSUPP;
+                               goto exit;
+                       }
+                        if ((res = dest_name_check(dest, m)))
+                                goto exit;
+                        res = tipc_multicast(tsock->p->ref,
+                                             &dest->addr.nameseq,
+                                             0,
+                                             m->msg_iovlen,
+                                             m->msg_iov);
+                }
+                if (likely(res != -ELINKCONG)) {
+exit:                                
+                        up(&tsock->sem);
+                        return res;
+                }
+               if (m->msg_flags & MSG_DONTWAIT) {
+                       res = -EWOULDBLOCK;
+                       goto exit;
+               }
+                if (wait_event_interruptible(*sock->sk->sk_sleep,
+                                             !tsock->p->congested)) {
+                    res = -ERESTARTSYS;
+                    goto exit;
+                }
+        } while (1);
+}
+
+/** 
+ * send_packet - send a connection-oriented message
+ * @iocb: (unused)
+ * @sock: socket structure
+ * @m: message to send
+ * @total_len: (unused)
+ * 
+ * Used for SOCK_SEQPACKET messages and SOCK_STREAM data.
+ * 
+ * Returns the number of bytes sent on success, or errno otherwise
+ */
+
+static int send_packet(struct kiocb *iocb, struct socket *sock,
+                      struct msghdr *m, size_t total_len)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+        struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
+       int res;
+
+       /* Handle implied connection establishment */
+
+       if (unlikely(dest))
+               return send_msg(iocb, sock, m, total_len);
+
+       if (down_interruptible(&tsock->sem)) {
+               return -ERESTARTSYS;
+        }
+
+        if (unlikely(sock->state != SS_CONNECTED)) {
+                if (sock->state == SS_DISCONNECTING)
+                        res = -EPIPE;   
+                else
+                        res = -ENOTCONN;
+                goto exit;
+        }
+
+        do {
+                res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
+                if (likely(res != -ELINKCONG)) {
+exit:
+                        up(&tsock->sem);
+                        return res;
+                }
+               if (m->msg_flags & MSG_DONTWAIT) {
+                       res = -EWOULDBLOCK;
+                       goto exit;
+               }
+                if (wait_event_interruptible(*sock->sk->sk_sleep,
+                                             !tsock->p->congested)) {
+                    res = -ERESTARTSYS;
+                    goto exit;
+                }
+        } while (1);
+}
+
+/** 
+ * send_stream - send stream-oriented data
+ * @iocb: (unused)
+ * @sock: socket structure
+ * @m: data to send
+ * @total_len: total length of data to be sent
+ * 
+ * Used for SOCK_STREAM data.
+ * 
+ * Returns the number of bytes sent on success, or errno otherwise
+ */
+
+
+static int send_stream(struct kiocb *iocb, struct socket *sock,
+                      struct msghdr *m, size_t total_len)
+{
+       struct msghdr my_msg;
+       struct iovec my_iov;
+       struct iovec *curr_iov;
+       int curr_iovlen;
+       char __user *curr_start;
+       int curr_left;
+       int bytes_to_send;
+       int res;
+       
+       if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
+               return send_packet(iocb, sock, m, total_len);
+
+       /* Can only send large data streams if already connected */
+
+        if (unlikely(sock->state != SS_CONNECTED)) {
+                if (sock->state == SS_DISCONNECTING)
+                        return -EPIPE;   
+                else
+                        return -ENOTCONN;
+        }
+
+       /* 
+        * Send each iovec entry using one or more messages
+        *
+        * Note: This algorithm is good for the most likely case 
+        * (i.e. one large iovec entry), but could be improved to pass sets
+        * of small iovec entries into send_packet().
+        */
+
+       my_msg = *m;
+       curr_iov = my_msg.msg_iov;
+       curr_iovlen = my_msg.msg_iovlen;
+       my_msg.msg_iov = &my_iov;
+       my_msg.msg_iovlen = 1;
+
+       while (curr_iovlen--) {
+               curr_start = curr_iov->iov_base;
+               curr_left = curr_iov->iov_len;
+
+               while (curr_left) {
+                       bytes_to_send = (curr_left < TIPC_MAX_USER_MSG_SIZE)
+                               ? curr_left : TIPC_MAX_USER_MSG_SIZE;
+                       my_iov.iov_base = curr_start;
+                       my_iov.iov_len = bytes_to_send;
+                        if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0)
+                                return res;
+                       curr_left -= bytes_to_send;
+                       curr_start += bytes_to_send;
+               }
+
+               curr_iov++;
+       }
+
+       return total_len;
+}
+
+/**
+ * auto_connect - complete connection setup to a remote port
+ * @sock: socket structure
+ * @tsock: TIPC-specific socket structure
+ * @msg: peer's response message
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int auto_connect(struct socket *sock, struct tipc_sock *tsock, 
+                       struct tipc_msg *msg)
+{
+       struct tipc_portid peer;
+
+       if (msg_errcode(msg)) {
+               sock->state = SS_DISCONNECTING;
+               return -ECONNREFUSED;
+       }
+
+       peer.ref = msg_origport(msg);
+       peer.node = msg_orignode(msg);
+       tipc_connect2port(tsock->p->ref, &peer);
+       tipc_set_portimportance(tsock->p->ref, msg_importance(msg));
+       sock->state = SS_CONNECTED;
+       return 0;
+}
+
+/**
+ * set_orig_addr - capture sender's address for received message
+ * @m: descriptor for message info
+ * @msg: received message header
+ * 
+ * Note: Address is not captured if not requested by receiver.
+ */
+
+static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
+{
+        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name;
+
+        if (addr) {
+               addr->family = AF_TIPC;
+               addr->addrtype = TIPC_ADDR_ID;
+               addr->addr.id.ref = msg_origport(msg);
+               addr->addr.id.node = msg_orignode(msg);
+               addr->addr.name.domain = 0;     /* could leave uninitialized */
+               addr->scope = 0;                /* could leave uninitialized */
+               m->msg_namelen = sizeof(struct sockaddr_tipc);
+       }
+}
+
+/**
+ * anc_data_recv - optionally capture ancillary data for received message 
+ * @m: descriptor for message info
+ * @msg: received message header
+ * @tport: TIPC port associated with message
+ * 
+ * Note: Ancillary data is not captured if not requested by receiver.
+ * 
+ * Returns 0 if successful, otherwise errno
+ */
+
+static inline int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, 
+                               struct tipc_port *tport)
+{
+       u32 anc_data[3];
+       u32 err;
+       u32 dest_type;
+       int res;
+
+       if (likely(m->msg_controllen == 0))
+               return 0;
+
+       /* Optionally capture errored message object(s) */
+
+       err = msg ? msg_errcode(msg) : 0;
+       if (unlikely(err)) {
+               anc_data[0] = err;
+               anc_data[1] = msg_data_sz(msg);
+               if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data)))
+                       return res;
+               if (anc_data[1] &&
+                   (res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1], 
+                                   msg_data(msg))))
+                       return res;
+       }
+
+       /* Optionally capture message destination object */
+
+       dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
+       switch (dest_type) {
+       case TIPC_NAMED_MSG:
+               anc_data[0] = msg_nametype(msg);
+               anc_data[1] = msg_namelower(msg);
+               anc_data[2] = msg_namelower(msg);
+               break;
+       case TIPC_MCAST_MSG:
+               anc_data[0] = msg_nametype(msg);
+               anc_data[1] = msg_namelower(msg);
+               anc_data[2] = msg_nameupper(msg);
+               break;
+       case TIPC_CONN_MSG:
+               anc_data[0] = tport->conn_type;
+               anc_data[1] = tport->conn_instance;
+               anc_data[2] = tport->conn_instance;
+               break;
+       default:
+               anc_data[0] = 0;
+       }
+       if (anc_data[0] &&
+           (res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data)))
+               return res;
+
+       return 0;
+}
+
+/** 
+ * recv_msg - receive packet-oriented message
+ * @iocb: (unused)
+ * @m: descriptor for message info
+ * @buf_len: total size of user buffer area
+ * @flags: receive flags
+ * 
+ * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages.
+ * If the complete message doesn't fit in user area, truncate it.
+ *
+ * Returns size of returned message data, errno otherwise
+ */
+
+static int recv_msg(struct kiocb *iocb, struct socket *sock,
+                   struct msghdr *m, size_t buf_len, int flags)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+       unsigned int q_len;
+       unsigned int sz;
+       u32 err;
+       int res;
+
+       /* Currently doesn't support receiving into multiple iovec entries */
+
+       if (m->msg_iovlen != 1)
+               return -EOPNOTSUPP;
+
+       /* Catch invalid receive attempts */
+
+       if (unlikely(!buf_len))
+               return -EINVAL;
+
+       if (sock->type == SOCK_SEQPACKET) {
+               if (unlikely(sock->state == SS_UNCONNECTED))
+                       return -ENOTCONN;
+               if (unlikely((sock->state == SS_DISCONNECTING) && 
+                            (skb_queue_len(&sock->sk->sk_receive_queue) == 0)))
+                       return -ENOTCONN;
+       }
+
+       /* Look for a message in receive queue; wait if necessary */
+
+       if (unlikely(down_interruptible(&tsock->sem)))
+               return -ERESTARTSYS;
+
+restart:
+       if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
+                    (flags & MSG_DONTWAIT))) {
+               res = -EWOULDBLOCK;
+               goto exit;
+       }
+
+       if ((res = wait_event_interruptible(
+               *sock->sk->sk_sleep, 
+               ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
+                (sock->state == SS_DISCONNECTING))) )) {
+               goto exit;
+       }
+
+       /* Catch attempt to receive on an already terminated connection */
+       /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
+
+       if (!q_len) {
+               res = -ENOTCONN;
+               goto exit;
+       }
+
+       /* Get access to first message in receive queue */
+
+       buf = skb_peek(&sock->sk->sk_receive_queue);
+       msg = buf_msg(buf);
+       sz = msg_data_sz(msg);
+       err = msg_errcode(msg);
+
+       /* Complete connection setup for an implied connect */
+
+       if (unlikely(sock->state == SS_CONNECTING)) {
+               if ((res = auto_connect(sock, tsock, msg)))
+                       goto exit;
+       }
+
+       /* Discard an empty non-errored message & try again */
+
+       if ((!sz) && (!err)) {
+               advance_queue(tsock);
+               goto restart;
+       }
+
+       /* Capture sender's address (optional) */
+
+       set_orig_addr(m, msg);
+
+       /* Capture ancillary data (optional) */
+
+       if ((res = anc_data_recv(m, msg, tsock->p)))
+               goto exit;
+
+       /* Capture message data (if valid) & compute return value (always) */
+       
+       if (!err) {
+               if (unlikely(buf_len < sz)) {
+                       sz = buf_len;
+                       m->msg_flags |= MSG_TRUNC;
+               }
+               if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg),
+                                         sz))) {
+                       res = -EFAULT;
+                       goto exit;
+               }
+               res = sz;
+       } else {
+               if ((sock->state == SS_READY) ||
+                   ((err == TIPC_CONN_SHUTDOWN) || m->msg_control))
+                       res = 0;
+               else
+                       res = -ECONNRESET;
+       }
+
+       /* Consume received message (optional) */
+
+       if (likely(!(flags & MSG_PEEK))) {
+                if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                        tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);
+               advance_queue(tsock);
+        }
+exit:
+       up(&tsock->sem);
+       return res;
+}
+
+/** 
+ * recv_stream - receive stream-oriented data
+ * @iocb: (unused)
+ * @m: descriptor for message info
+ * @buf_len: total size of user buffer area
+ * @flags: receive flags
+ * 
+ * Used for SOCK_STREAM messages only.  If not enough data is available 
+ * will optionally wait for more; never truncates data.
+ *
+ * Returns size of returned message data, errno otherwise
+ */
+
+static int recv_stream(struct kiocb *iocb, struct socket *sock,
+                      struct msghdr *m, size_t buf_len, int flags)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct sk_buff *buf;
+       struct tipc_msg *msg;
+       unsigned int q_len;
+       unsigned int sz;
+       int sz_to_copy;
+       int sz_copied = 0;
+       int needed;
+       char *crs = m->msg_iov->iov_base;
+       unsigned char *buf_crs;
+       u32 err;
+       int res;
+
+       /* Currently doesn't support receiving into multiple iovec entries */
+
+       if (m->msg_iovlen != 1)
+               return -EOPNOTSUPP;
+
+       /* Catch invalid receive attempts */
+
+       if (unlikely(!buf_len))
+               return -EINVAL;
+
+       if (unlikely(sock->state == SS_DISCONNECTING)) {
+               if (skb_queue_len(&sock->sk->sk_receive_queue) == 0)
+                       return -ENOTCONN;
+       } else if (unlikely(sock->state != SS_CONNECTED))
+               return -ENOTCONN;
+
+       /* Look for a message in receive queue; wait if necessary */
+
+       if (unlikely(down_interruptible(&tsock->sem)))
+               return -ERESTARTSYS;
+
+restart:
+       if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
+                    (flags & MSG_DONTWAIT))) {
+               res = (sz_copied == 0) ? -EWOULDBLOCK : 0;
+               goto exit;
+       }
+
+       if ((res = wait_event_interruptible(
+               *sock->sk->sk_sleep, 
+               ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
+                (sock->state == SS_DISCONNECTING))) )) {
+               goto exit;
+       }
+
+       /* Catch attempt to receive on an already terminated connection */
+       /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
+
+       if (!q_len) {
+               res = -ENOTCONN;
+               goto exit;
+       }
+
+       /* Get access to first message in receive queue */
+
+       buf = skb_peek(&sock->sk->sk_receive_queue);
+       msg = buf_msg(buf);
+       sz = msg_data_sz(msg);
+       err = msg_errcode(msg);
+
+       /* Discard an empty non-errored message & try again */
+
+       if ((!sz) && (!err)) {
+               advance_queue(tsock);
+               goto restart;
+       }
+
+       /* Optionally capture sender's address & ancillary data of first msg */
+
+       if (sz_copied == 0) {
+               set_orig_addr(m, msg);
+               if ((res = anc_data_recv(m, msg, tsock->p)))
+                       goto exit;
+       }
+
+       /* Capture message data (if valid) & compute return value (always) */
+       
+       if (!err) {
+               buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle);
+               sz = buf->tail - buf_crs;
+
+               needed = (buf_len - sz_copied);
+               sz_to_copy = (sz <= needed) ? sz : needed;
+               if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) {
+                       res = -EFAULT;
+                       goto exit;
+               }
+               sz_copied += sz_to_copy;
+
+               if (sz_to_copy < sz) {
+                       if (!(flags & MSG_PEEK))
+                               TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy;
+                       goto exit;
+               }
+
+               crs += sz_to_copy;
+       } else {
+               if (sz_copied != 0)
+                       goto exit; /* can't add error msg to valid data */
+
+               if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)
+                       res = 0;
+               else
+                       res = -ECONNRESET;
+       }
+
+       /* Consume received message (optional) */
+
+       if (likely(!(flags & MSG_PEEK))) {
+                if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                        tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);
+               advance_queue(tsock);
+        }
+
+       /* Loop around if more data is required */
+
+       if ((sz_copied < buf_len)    /* didn't get all requested data */ 
+           && (flags & MSG_WAITALL) /* ... and need to wait for more */
+           && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */
+           && (!err)                /* ... and haven't reached a FIN */
+           )
+               goto restart;
+
+exit:
+       up(&tsock->sem);
+       return res ? res : sz_copied;
+}
+
+/**
+ * queue_overloaded - test if queue overload condition exists
+ * @queue_size: current size of queue
+ * @base: nominal maximum size of queue
+ * @msg: message to be added to queue
+ * 
+ * Returns 1 if queue is currently overloaded, 0 otherwise
+ */
+
+static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg)
+{
+       u32 threshold;
+       u32 imp = msg_importance(msg);
+
+       if (imp == TIPC_LOW_IMPORTANCE)
+               threshold = base;
+       else if (imp == TIPC_MEDIUM_IMPORTANCE)
+               threshold = base * 2;
+       else if (imp == TIPC_HIGH_IMPORTANCE)
+               threshold = base * 100;
+       else
+               return 0;
+
+       if (msg_connected(msg))
+               threshold *= 4;
+
+       return (queue_size > threshold);
+}
+
+/** 
+ * async_disconnect - wrapper function used to disconnect port
+ * @portref: TIPC port reference (passed as pointer-sized value)
+ */
+
+static void async_disconnect(unsigned long portref)
+{
+       tipc_disconnect((u32)portref);
+}
+
+/** 
+ * dispatch - handle arriving message
+ * @tport: TIPC port that received message
+ * @buf: message
+ * 
+ * Called with port locked.  Must not take socket lock to avoid deadlock risk.
+ * 
+ * Returns TIPC error status code (TIPC_OK if message is not to be rejected)
+ */
+
+static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
+{
+       struct tipc_msg *msg = buf_msg(buf);
+       struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
+       struct socket *sock;
+       u32 recv_q_len;
+
+       /* Reject message if socket is closing */
+
+       if (!tsock)
+               return TIPC_ERR_NO_PORT;
+
+       /* Reject message if it is wrong sort of message for socket */
+
+       /*
+        * WOULD IT BE BETTER TO JUST DISCARD THESE MESSAGES INSTEAD?
+        * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY
+        * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC
+        */
+       sock = tsock->sk.sk_socket;
+       if (sock->state == SS_READY) {
+               if (msg_connected(msg)) {
+                       msg_dbg(msg, "dispatch filter 1\n");
+                       return TIPC_ERR_NO_PORT;
+               }
+       } else {
+               if (msg_mcast(msg)) {
+                       msg_dbg(msg, "dispatch filter 2\n");
+                       return TIPC_ERR_NO_PORT;
+               }
+               if (sock->state == SS_CONNECTED) {
+                       if (!msg_connected(msg)) {
+                               msg_dbg(msg, "dispatch filter 3\n");
+                               return TIPC_ERR_NO_PORT;
+                       }
+               }
+               else if (sock->state == SS_CONNECTING) {
+                       if (!msg_connected(msg) && (msg_errcode(msg) == 0)) {
+                               msg_dbg(msg, "dispatch filter 4\n");
+                               return TIPC_ERR_NO_PORT;
+                       }
+               } 
+               else if (sock->state == SS_LISTENING) {
+                       if (msg_connected(msg) || msg_errcode(msg)) {
+                               msg_dbg(msg, "dispatch filter 5\n");
+                               return TIPC_ERR_NO_PORT;
+                       }
+               } 
+               else if (sock->state == SS_DISCONNECTING) {
+                       msg_dbg(msg, "dispatch filter 6\n");
+                       return TIPC_ERR_NO_PORT;
+               }
+               else /* (sock->state == SS_UNCONNECTED) */ {
+                       if (msg_connected(msg) || msg_errcode(msg)) {
+                               msg_dbg(msg, "dispatch filter 7\n");
+                               return TIPC_ERR_NO_PORT;
+                       }
+               }
+       }
+
+       /* Reject message if there isn't room to queue it */
+
+       if (unlikely((u32)atomic_read(&tipc_queue_size) > 
+                    OVERLOAD_LIMIT_BASE)) {
+               if (queue_overloaded(atomic_read(&tipc_queue_size), 
+                                    OVERLOAD_LIMIT_BASE, msg))
+                       return TIPC_ERR_OVERLOAD;
+        }
+       recv_q_len = skb_queue_len(&tsock->sk.sk_receive_queue);
+       if (unlikely(recv_q_len > (OVERLOAD_LIMIT_BASE / 2))) {
+               if (queue_overloaded(recv_q_len, 
+                                    OVERLOAD_LIMIT_BASE / 2, msg)) 
+                       return TIPC_ERR_OVERLOAD;
+        }
+
+       /* Initiate connection termination for an incoming 'FIN' */
+
+       if (unlikely(msg_errcode(msg) && (sock->state == SS_CONNECTED))) {
+               sock->state = SS_DISCONNECTING;
+               /* Note: Use signal since port lock is already taken! */
+               k_signal((Handler)async_disconnect, tport->ref);
+       }
+
+       /* Enqueue message (finally!) */
+
+       msg_dbg(msg,"<DISP<: ");
+       TIPC_SKB_CB(buf)->handle = msg_data(msg);
+       atomic_inc(&tipc_queue_size);
+       skb_queue_tail(&sock->sk->sk_receive_queue, buf);
+
+        wake_up_interruptible(sock->sk->sk_sleep);
+       return TIPC_OK;
+}
+
+/** 
+ * wakeupdispatch - wake up port after congestion
+ * @tport: port to wakeup
+ * 
+ * Called with port lock on.
+ */
+
+static void wakeupdispatch(struct tipc_port *tport)
+{
+       struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
+
+        wake_up_interruptible(tsock->sk.sk_sleep);
+}
+
+/**
+ * connect - establish a connection to another TIPC port
+ * @sock: socket structure
+ * @dest: socket address for destination port
+ * @destlen: size of socket address data structure
+ * @flags: (unused)
+ *
+ * Returns 0 on success, errno otherwise
+ */
+
+static int connect(struct socket *sock, struct sockaddr *dest, int destlen, 
+                  int flags)
+{
+   struct tipc_sock *tsock = tipc_sk(sock->sk);
+   struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
+   struct msghdr m = {0,};
+   struct sk_buff *buf;
+   struct tipc_msg *msg;
+   int res;
+
+   /* For now, TIPC does not allow use of connect() with DGRAM or RDM types */
+
+   if (sock->state == SS_READY)
+          return -EOPNOTSUPP;
+
+   /* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */
+   if (sock->state == SS_LISTENING)
+          return -EOPNOTSUPP;
+   if (sock->state == SS_CONNECTING)
+          return -EALREADY;
+   if (sock->state != SS_UNCONNECTED)
+           return -EISCONN;
+
+   if ((dst->family != AF_TIPC) ||
+       ((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID)))
+           return -EINVAL;
+
+   /* Send a 'SYN-' to destination */
+
+   m.msg_name = dest;
+   if ((res = send_msg(0, sock, &m, 0)) < 0) {
+          sock->state = SS_DISCONNECTING;
+          return res;
+   }
+
+   if (down_interruptible(&tsock->sem)) 
+           return -ERESTARTSYS;
+       
+   /* Wait for destination's 'ACK' response */
+
+   res = wait_event_interruptible_timeout(*sock->sk->sk_sleep,
+                                          skb_queue_len(&sock->sk->sk_receive_queue),
+                                         sock->sk->sk_rcvtimeo);
+   buf = skb_peek(&sock->sk->sk_receive_queue);
+   if (res > 0) {
+          msg = buf_msg(buf);
+           res = auto_connect(sock, tsock, msg);
+           if (!res) {
+                  if (dst->addrtype == TIPC_ADDR_NAME) {
+                          tsock->p->conn_type = dst->addr.name.name.type;
+                          tsock->p->conn_instance = dst->addr.name.name.instance;
+                  }
+                  if (!msg_data_sz(msg))
+                          advance_queue(tsock);
+          }
+   } else {
+          if (res == 0) {
+                  res = -ETIMEDOUT;
+          } else
+                  { /* leave "res" unchanged */ }
+          sock->state = SS_DISCONNECTING;
+   }
+
+   up(&tsock->sem);
+   return res;
+}
+
+/** 
+ * listen - allow socket to listen for incoming connections
+ * @sock: socket structure
+ * @len: (unused)
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int listen(struct socket *sock, int len)
+{
+       /* REQUIRES SOCKET LOCKING OF SOME SORT? */
+
+       if (sock->state == SS_READY)
+               return -EOPNOTSUPP;
+       if (sock->state != SS_UNCONNECTED)
+               return -EINVAL;
+       sock->state = SS_LISTENING;
+        return 0;
+}
+
+/** 
+ * accept - wait for connection request
+ * @sock: listening socket
+ * @newsock: new socket that is to be connected
+ * @flags: file-related flags associated with socket
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int accept(struct socket *sock, struct socket *newsock, int flags)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct sk_buff *buf;
+       int res = -EFAULT;
+
+       if (sock->state == SS_READY)
+               return -EOPNOTSUPP;
+       if (sock->state != SS_LISTENING)
+               return -EINVAL;
+       
+       if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && 
+                    (flags & O_NONBLOCK)))
+               return -EWOULDBLOCK;
+
+       if (down_interruptible(&tsock->sem))
+               return -ERESTARTSYS;
+
+       if (wait_event_interruptible(*sock->sk->sk_sleep, 
+                                    skb_queue_len(&sock->sk->sk_receive_queue))) {
+               res = -ERESTARTSYS;
+               goto exit;
+       }
+       buf = skb_peek(&sock->sk->sk_receive_queue);
+
+       res = tipc_create(newsock, 0);
+       if (!res) {
+               struct tipc_sock *new_tsock = tipc_sk(newsock->sk);
+               struct tipc_portid id;
+               struct tipc_msg *msg = buf_msg(buf);
+               u32 new_ref = new_tsock->p->ref;
+
+               id.ref = msg_origport(msg);
+               id.node = msg_orignode(msg);
+               tipc_connect2port(new_ref, &id);
+               newsock->state = SS_CONNECTED;
+
+               tipc_set_portimportance(new_ref, msg_importance(msg));
+               if (msg_named(msg)) {
+                       new_tsock->p->conn_type = msg_nametype(msg);
+                       new_tsock->p->conn_instance = msg_nameinst(msg);
+               }
+
+               /* 
+                * Respond to 'SYN-' by discarding it & returning 'ACK'-.
+                * Respond to 'SYN+' by queuing it on new socket.
+                */
+
+               msg_dbg(msg,"<ACC<: ");
+                if (!msg_data_sz(msg)) {
+                        struct msghdr m = {0,};
+
+                        send_packet(0, newsock, &m, 0);      
+                        advance_queue(tsock);
+                } else {
+                       sock_lock(tsock);
+                       skb_dequeue(&sock->sk->sk_receive_queue);
+                       sock_unlock(tsock);
+                       skb_queue_head(&newsock->sk->sk_receive_queue, buf);
+               }
+       }
+exit:
+       up(&tsock->sem);
+       return res;
+}
+
+/**
+ * shutdown - shutdown socket connection
+ * @sock: socket structure
+ * @how: direction to close (always treated as read + write)
+ *
+ * Terminates connection (if necessary), then purges socket's receive queue.
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int shutdown(struct socket *sock, int how)
+{
+       struct tipc_sock* tsock = tipc_sk(sock->sk);
+       struct sk_buff *buf;
+       int res;
+
+       /* Could return -EINVAL for an invalid "how", but why bother? */
+
+       if (down_interruptible(&tsock->sem))
+               return -ERESTARTSYS;
+
+       sock_lock(tsock);
+
+       switch (sock->state) {
+       case SS_CONNECTED:
+
+               /* Send 'FIN+' or 'FIN-' message to peer */
+
+               sock_unlock(tsock);
+restart:
+               if ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
+                       atomic_dec(&tipc_queue_size);
+                       if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) {
+                               buf_discard(buf);
+                               goto restart;
+                       }
+                       tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN);
+               }
+               else {
+                       tipc_shutdown(tsock->p->ref);
+               }
+               sock_lock(tsock);
+
+               /* fall through */
+
+       case SS_DISCONNECTING:
+
+               /* Discard any unreceived messages */
+
+               while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
+                       atomic_dec(&tipc_queue_size);
+                       buf_discard(buf);
+               }
+               tsock->p->conn_unacked = 0;
+
+               /* fall through */
+
+       case SS_CONNECTING:
+               sock->state = SS_DISCONNECTING;
+               res = 0;
+               break;
+
+       default:
+               res = -ENOTCONN;
+       }
+
+       sock_unlock(tsock);
+
+       up(&tsock->sem);
+       return res;
+}
+
+/**
+ * setsockopt - set socket option
+ * @sock: socket structure
+ * @lvl: option level
+ * @opt: option identifier
+ * @ov: pointer to new option value
+ * @ol: length of option value
+ * 
+ * For stream sockets only, accepts and ignores all IPPROTO_TCP options 
+ * (to ease compatibility).
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       u32 value;
+       int res;
+
+        if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
+                return 0;
+       if (lvl != SOL_TIPC)
+               return -ENOPROTOOPT;
+       if (ol < sizeof(value))
+               return -EINVAL;
+        if ((res = get_user(value, (u32 *)ov)))
+               return res;
+
+       if (down_interruptible(&tsock->sem)) 
+               return -ERESTARTSYS;
+       
+       switch (opt) {
+       case TIPC_IMPORTANCE:
+               res = tipc_set_portimportance(tsock->p->ref, value);
+               break;
+       case TIPC_SRC_DROPPABLE:
+               if (sock->type != SOCK_STREAM)
+                       res = tipc_set_portunreliable(tsock->p->ref, value);
+               else 
+                       res = -ENOPROTOOPT;
+               break;
+       case TIPC_DEST_DROPPABLE:
+               res = tipc_set_portunreturnable(tsock->p->ref, value);
+               break;
+       case TIPC_CONN_TIMEOUT:
+               sock->sk->sk_rcvtimeo = (value * HZ / 1000);
+               break;
+       default:
+               res = -EINVAL;
+       }
+
+       up(&tsock->sem);
+       return res;
+}
+
+/**
+ * getsockopt - get socket option
+ * @sock: socket structure
+ * @lvl: option level
+ * @opt: option identifier
+ * @ov: receptacle for option value
+ * @ol: receptacle for length of option value
+ * 
+ * For stream sockets only, returns 0 length result for all IPPROTO_TCP options 
+ * (to ease compatibility).
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+
+static int getsockopt(struct socket *sock, int lvl, int opt, char *ov, int *ol)
+{
+       struct tipc_sock *tsock = tipc_sk(sock->sk);
+        int len;
+       u32 value;
+        int res;
+
+        if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
+                return put_user(0, ol);
+       if (lvl != SOL_TIPC)
+               return -ENOPROTOOPT;
+        if ((res = get_user(len, ol)))
+                return res;
+
+       if (down_interruptible(&tsock->sem)) 
+               return -ERESTARTSYS;
+
+       switch (opt) {
+       case TIPC_IMPORTANCE:
+               res = tipc_portimportance(tsock->p->ref, &value);
+               break;
+       case TIPC_SRC_DROPPABLE:
+               res = tipc_portunreliable(tsock->p->ref, &value);
+               break;
+       case TIPC_DEST_DROPPABLE:
+               res = tipc_portunreturnable(tsock->p->ref, &value);
+               break;
+       case TIPC_CONN_TIMEOUT:
+               value = (sock->sk->sk_rcvtimeo * 1000) / HZ;
+               break;
+       default:
+               res = -EINVAL;
+       }
+
+       if (res) {
+               /* "get" failed */
+       }
+       else if (len < sizeof(value)) {
+               res = -EINVAL;
+       }
+       else if ((res = copy_to_user(ov, &value, sizeof(value)))) {
+               /* couldn't return value */
+       }
+       else {
+               res = put_user(sizeof(value), ol);
+       }
+
+        up(&tsock->sem);
+       return res;
+}
+
+/**
+ * Placeholders for non-implemented functionality
+ * 
+ * Returns error code (POSIX-compliant where defined)
+ */
+
+static int ioctl(struct socket *s, u32 cmd, unsigned long arg)
+{
+        return -EINVAL;
+}
+
+static int no_mmap(struct file *file, struct socket *sock,
+                   struct vm_area_struct *vma)
+{
+        return -EINVAL;
+}
+static ssize_t no_sendpage(struct socket *sock, struct page *page,
+                           int offset, size_t size, int flags)
+{
+        return -EINVAL;
+}
+
+static int no_skpair(struct socket *s1, struct socket *s2)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ * Protocol switches for the various types of TIPC sockets
+ */
+
+static struct proto_ops msg_ops = {
+       .owner          = THIS_MODULE,
+       .family         = AF_TIPC,
+       .release        = release,
+       .bind           = bind,
+       .connect        = connect,
+       .socketpair     = no_skpair,
+       .accept         = accept,
+       .getname        = get_name,
+       .poll           = poll,
+       .ioctl          = ioctl,
+       .listen         = listen,
+       .shutdown       = shutdown,
+       .setsockopt     = setsockopt,
+       .getsockopt     = getsockopt,
+       .sendmsg        = send_msg,
+       .recvmsg        = recv_msg,
+        .mmap          = no_mmap,
+        .sendpage      = no_sendpage
+};
+
+static struct proto_ops packet_ops = {
+       .owner          = THIS_MODULE,
+       .family         = AF_TIPC,
+       .release        = release,
+       .bind           = bind,
+       .connect        = connect,
+       .socketpair     = no_skpair,
+       .accept         = accept,
+       .getname        = get_name,
+       .poll           = poll,
+       .ioctl          = ioctl,
+       .listen         = listen,
+       .shutdown       = shutdown,
+       .setsockopt     = setsockopt,
+       .getsockopt     = getsockopt,
+       .sendmsg        = send_packet,
+       .recvmsg        = recv_msg,
+        .mmap          = no_mmap,
+        .sendpage      = no_sendpage
+};
+
+static struct proto_ops stream_ops = {
+       .owner          = THIS_MODULE,
+       .family         = AF_TIPC,
+       .release        = release,
+       .bind           = bind,
+       .connect        = connect,
+       .socketpair     = no_skpair,
+       .accept         = accept,
+       .getname        = get_name,
+       .poll           = poll,
+       .ioctl          = ioctl,
+       .listen         = listen,
+       .shutdown       = shutdown,
+       .setsockopt     = setsockopt,
+       .getsockopt     = getsockopt,
+       .sendmsg        = send_stream,
+       .recvmsg        = recv_stream,
+        .mmap          = no_mmap,
+        .sendpage      = no_sendpage
+};
+
+static struct net_proto_family tipc_family_ops = {
+       .owner          = THIS_MODULE,
+       .family         = AF_TIPC,
+       .create         = tipc_create
+};
+
+static struct proto tipc_proto = {
+       .name           = "TIPC",
+       .owner          = THIS_MODULE,
+       .obj_size       = sizeof(struct tipc_sock)
+};
+
+/**
+ * socket_init - initialize TIPC socket interface
+ * 
+ * Returns 0 on success, errno otherwise
+ */
+int socket_init(void)
+{
+       int res;
+
+        res = proto_register(&tipc_proto, 1);
+       if (res) {
+               err("Failed to register TIPC protocol type\n");
+               goto out;
+       }
+
+       res = sock_register(&tipc_family_ops);
+       if (res) {
+               err("Failed to register TIPC socket type\n");
+               proto_unregister(&tipc_proto);
+               goto out;
+       }
+
+       sockets_enabled = 1;
+ out:
+       return res;
+}
+
+/**
+ * sock_stop - stop TIPC socket interface
+ */
+void socket_stop(void)
+{
+       if (!sockets_enabled)
+               return;
+
+       sockets_enabled = 0;
+       sock_unregister(tipc_family_ops.family);
+       proto_unregister(&tipc_proto);
+}
+
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
new file mode 100644 (file)
index 0000000..80e219b
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * net/tipc/subscr.c: TIPC subscription service
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "subscr.h"
+#include "name_table.h"
+#include "ref.h"
+
+/**
+ * struct subscriber - TIPC network topology subscriber
+ * @ref: object reference to subscriber object itself
+ * @lock: pointer to spinlock controlling access to subscriber object
+ * @subscriber_list: adjacent subscribers in top. server's list of subscribers
+ * @subscription_list: list of subscription objects for this subscriber
+ * @port_ref: object reference to port used to communicate with subscriber
+ * @swap: indicates if subscriber uses opposite endianness in its messages
+ */
+struct subscriber {
+       u32 ref;
+        spinlock_t *lock;
+       struct list_head subscriber_list;
+       struct list_head subscription_list;
+       u32 port_ref;
+       int swap;
+};
+
+/**
+ * struct top_srv - TIPC network topology subscription service
+ * @user_ref: TIPC userid of subscription service
+ * @setup_port: reference to TIPC port that handles subscription requests
+ * @subscription_count: number of active subscriptions (not subscribers!)
+ * @subscriber_list: list of ports subscribing to service
+ * @lock: spinlock govering access to subscriber list
+ */
+
+struct top_srv {
+       u32 user_ref;
+       u32 setup_port;
+       atomic_t subscription_count;
+       struct list_head subscriber_list;
+       spinlock_t lock;
+};
+
+static struct top_srv topsrv = { 0 };
+
+/**
+ * htohl - convert value to endianness used by destination
+ * @in: value to convert
+ * @swap: non-zero if endianness must be reversed
+ * 
+ * Returns converted value
+ */
+
+static inline u32 htohl(u32 in, int swap)
+{
+       char *c = (char *)&in;
+
+       return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
+}
+
+/**
+ * subscr_send_event - send a message containing a tipc_event to the subscriber
+ */
+
+static void subscr_send_event(struct subscription *sub, 
+                             u32 found_lower, 
+                             u32 found_upper,
+                             u32 event, 
+                             u32 port_ref, 
+                             u32 node)
+{
+       struct iovec msg_sect;
+
+       msg_sect.iov_base = (void *)&sub->evt;
+       msg_sect.iov_len = sizeof(struct tipc_event);
+
+       sub->evt.event = htohl(event, sub->owner->swap);
+       sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
+       sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
+       sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
+       sub->evt.port.node = htohl(node, sub->owner->swap);
+       tipc_send(sub->owner->port_ref, 1, &msg_sect);
+}
+
+/**
+ * subscr_overlap - test for subscription overlap with the given values
+ *
+ * Returns 1 if there is overlap, otherwise 0.
+ */
+
+int subscr_overlap(struct subscription *sub, 
+                  u32 found_lower, 
+                  u32 found_upper)
+
+{
+       if (found_lower < sub->seq.lower)
+               found_lower = sub->seq.lower;
+       if (found_upper > sub->seq.upper)
+               found_upper = sub->seq.upper;
+       if (found_lower > found_upper)
+               return 0;
+       return 1;
+}
+
+/**
+ * subscr_report_overlap - issue event if there is subscription overlap
+ * 
+ * Protected by nameseq.lock in name_table.c
+ */
+
+void subscr_report_overlap(struct subscription *sub, 
+                          u32 found_lower, 
+                          u32 found_upper,
+                          u32 event, 
+                          u32 port_ref, 
+                          u32 node,
+                          int must)
+{
+       dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
+           sub->seq.upper, found_lower, found_upper);
+       if (!subscr_overlap(sub, found_lower, found_upper))
+               return;
+       if (!must && (sub->filter != TIPC_SUB_PORTS))
+               return;
+       subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
+}
+
+/**
+ * subscr_timeout - subscription timeout has occurred
+ */
+
+static void subscr_timeout(struct subscription *sub)
+{
+       struct subscriber *subscriber;
+       u32 subscriber_ref;
+
+       /* Validate subscriber reference (in case subscriber is terminating) */
+
+       subscriber_ref = sub->owner->ref;
+       subscriber = (struct subscriber *)ref_lock(subscriber_ref);
+       if (subscriber == NULL)
+               return;
+
+       /* Unlink subscription from name table */
+
+       nametbl_unsubscribe(sub);
+
+       /* Notify subscriber of timeout, then unlink subscription */
+
+       subscr_send_event(sub, 
+                         sub->evt.s.seq.lower, 
+                         sub->evt.s.seq.upper,
+                         TIPC_SUBSCR_TIMEOUT, 
+                         0, 
+                         0);
+       list_del(&sub->subscription_list);
+
+       /* Now destroy subscription */
+
+       ref_unlock(subscriber_ref);
+       k_term_timer(&sub->timer);
+       kfree(sub);
+       atomic_dec(&topsrv.subscription_count);
+}
+
+/**
+ * subscr_terminate - terminate communication with a subscriber
+ * 
+ * Called with subscriber locked.  Routine must temporarily release this lock
+ * to enable subscription timeout routine(s) to finish without deadlocking; 
+ * the lock is then reclaimed to allow caller to release it upon return.
+ * (This should work even in the unlikely event some other thread creates 
+ * a new object reference in the interim that uses this lock; this routine will
+ * simply wait for it to be released, then claim it.)
+ */
+
+static void subscr_terminate(struct subscriber *subscriber)
+{
+       struct subscription *sub;
+       struct subscription *sub_temp;
+
+       /* Invalidate subscriber reference */
+
+       ref_discard(subscriber->ref);
+       spin_unlock_bh(subscriber->lock);
+
+       /* Destroy any existing subscriptions for subscriber */
+       
+       list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
+                                subscription_list) {
+               if (sub->timeout != TIPC_WAIT_FOREVER) {
+                       k_cancel_timer(&sub->timer);
+                       k_term_timer(&sub->timer);
+               }
+               nametbl_unsubscribe(sub);
+               list_del(&sub->subscription_list);
+               dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
+                   sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
+               kfree(sub);
+               atomic_dec(&topsrv.subscription_count);
+       }
+
+       /* Sever connection to subscriber */
+
+       tipc_shutdown(subscriber->port_ref);
+       tipc_deleteport(subscriber->port_ref);
+
+       /* Remove subscriber from topology server's subscriber list */
+
+       spin_lock_bh(&topsrv.lock);
+       list_del(&subscriber->subscriber_list);
+       spin_unlock_bh(&topsrv.lock);
+
+       /* Now destroy subscriber */
+
+       spin_lock_bh(subscriber->lock);
+       kfree(subscriber);
+}
+
+/**
+ * subscr_subscribe - create subscription for subscriber
+ * 
+ * Called with subscriber locked
+ */
+
+static void subscr_subscribe(struct tipc_subscr *s,
+                            struct subscriber *subscriber)
+{
+       struct subscription *sub;
+
+       /* Refuse subscription if global limit exceeded */
+
+       if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
+               warn("Failed: max %u subscriptions\n", tipc_max_subscriptions);
+               subscr_terminate(subscriber);
+               return;
+       }
+
+       /* Allocate subscription object */
+
+       sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
+       if (sub == NULL) {
+               warn("Memory squeeze; ignoring subscription\n");
+               subscr_terminate(subscriber);
+               return;
+       }
+
+       /* Determine/update subscriber's endianness */
+
+       if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
+               subscriber->swap = 0;
+       else
+               subscriber->swap = 1;
+
+       /* Initialize subscription object */
+
+       memset(sub, 0, sizeof(*sub));
+       sub->seq.type = htohl(s->seq.type, subscriber->swap);
+       sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
+       sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
+       sub->timeout = htohl(s->timeout, subscriber->swap);
+       sub->filter = htohl(s->filter, subscriber->swap);
+       if ((((sub->filter != TIPC_SUB_PORTS) 
+             && (sub->filter != TIPC_SUB_SERVICE)))
+           || (sub->seq.lower > sub->seq.upper)) {
+               warn("Rejecting illegal subscription %u,%u,%u\n",
+                    sub->seq.type, sub->seq.lower, sub->seq.upper);
+               kfree(sub);
+               subscr_terminate(subscriber);
+               return;
+       }
+       memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
+       INIT_LIST_HEAD(&sub->subscription_list);
+       INIT_LIST_HEAD(&sub->nameseq_list);
+       list_add(&sub->subscription_list, &subscriber->subscription_list);
+       atomic_inc(&topsrv.subscription_count);
+       if (sub->timeout != TIPC_WAIT_FOREVER) {
+               k_init_timer(&sub->timer,
+                            (Handler)subscr_timeout, (unsigned long)sub);
+               k_start_timer(&sub->timer, sub->timeout);
+       }
+       sub->owner = subscriber;
+       nametbl_subscribe(sub);
+}
+
+/**
+ * subscr_conn_shutdown_event - handle termination request from subscriber
+ */
+
+static void subscr_conn_shutdown_event(void *usr_handle,
+                                      u32 portref,
+                                      struct sk_buff **buf,
+                                      unsigned char const *data,
+                                      unsigned int size,
+                                      int reason)
+{
+       struct subscriber *subscriber;
+       spinlock_t *subscriber_lock;
+
+       subscriber = ref_lock((u32)(unsigned long)usr_handle);
+       if (subscriber == NULL)
+               return;
+
+       subscriber_lock = subscriber->lock;
+       subscr_terminate(subscriber);
+       spin_unlock_bh(subscriber_lock);
+}
+
+/**
+ * subscr_conn_msg_event - handle new subscription request from subscriber
+ */
+
+static void subscr_conn_msg_event(void *usr_handle,
+                                 u32 port_ref,
+                                 struct sk_buff **buf,
+                                 const unchar *data,
+                                 u32 size)
+{
+       struct subscriber *subscriber;
+       spinlock_t *subscriber_lock;
+
+       subscriber = ref_lock((u32)(unsigned long)usr_handle);
+       if (subscriber == NULL)
+               return;
+
+       subscriber_lock = subscriber->lock;
+       if (size != sizeof(struct tipc_subscr))
+               subscr_terminate(subscriber);
+       else
+               subscr_subscribe((struct tipc_subscr *)data, subscriber);
+       
+       spin_unlock_bh(subscriber_lock);
+}
+
+/**
+ * subscr_named_msg_event - handle request to establish a new subscriber
+ */
+
+static void subscr_named_msg_event(void *usr_handle,
+                                  u32 port_ref,
+                                  struct sk_buff **buf,
+                                  const unchar *data,
+                                  u32 size,
+                                  u32 importance, 
+                                  struct tipc_portid const *orig,
+                                  struct tipc_name_seq const *dest)
+{
+       struct subscriber *subscriber;
+       struct iovec msg_sect = {0, 0};
+       spinlock_t *subscriber_lock;
+
+       dbg("subscr_named_msg_event: orig = %x own = %x,\n",
+           orig->node, tipc_own_addr);
+       if (size && (size != sizeof(struct tipc_subscr))) {
+               warn("Received tipc_subscr of invalid size\n");
+               return;
+       }
+
+       /* Create subscriber object */
+
+       subscriber = kmalloc(sizeof(struct subscriber), GFP_ATOMIC);
+       if (subscriber == NULL) {
+               warn("Memory squeeze; ignoring subscriber setup\n");
+               return;
+       }
+       memset(subscriber, 0, sizeof(struct subscriber));
+       INIT_LIST_HEAD(&subscriber->subscription_list);
+       INIT_LIST_HEAD(&subscriber->subscriber_list);
+       subscriber->ref = ref_acquire(subscriber, &subscriber->lock);
+       if (subscriber->ref == 0) {
+               warn("Failed to acquire subscriber reference\n");
+               kfree(subscriber);
+               return;
+       }
+
+       /* Establish a connection to subscriber */
+
+       tipc_createport(topsrv.user_ref,
+                       (void *)(unsigned long)subscriber->ref,
+                       importance,
+                       0,
+                       0,
+                       subscr_conn_shutdown_event,
+                       0,
+                       0,
+                       subscr_conn_msg_event,
+                       0,
+                       &subscriber->port_ref);
+       if (subscriber->port_ref == 0) {
+               warn("Memory squeeze; failed to create subscription port\n");
+               ref_discard(subscriber->ref);
+               kfree(subscriber);
+               return;
+       }
+       tipc_connect2port(subscriber->port_ref, orig);
+
+
+       /* Add subscriber to topology server's subscriber list */
+
+       ref_lock(subscriber->ref);
+       spin_lock_bh(&topsrv.lock);
+       list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
+       spin_unlock_bh(&topsrv.lock);
+
+       /*
+        * Subscribe now if message contains a subscription,
+        * otherwise send an empty response to complete connection handshaking
+        */
+
+       subscriber_lock = subscriber->lock;
+       if (size)
+               subscr_subscribe((struct tipc_subscr *)data, subscriber);
+       else
+               tipc_send(subscriber->port_ref, 1, &msg_sect);
+
+       spin_unlock_bh(subscriber_lock);
+}
+
+int subscr_start(void)
+{
+       struct tipc_name_seq seq = {TIPC_TOP_SRV, TIPC_TOP_SRV, TIPC_TOP_SRV};
+       int res = -1;
+
+       memset(&topsrv, 0, sizeof (topsrv));
+       topsrv.lock = SPIN_LOCK_UNLOCKED;
+       INIT_LIST_HEAD(&topsrv.subscriber_list);
+
+       spin_lock_bh(&topsrv.lock);
+       res = tipc_attach(&topsrv.user_ref, 0, 0);
+       if (res) {
+               spin_unlock_bh(&topsrv.lock);
+               return res;
+       }
+
+       res = tipc_createport(topsrv.user_ref,
+                             0,
+                             TIPC_CRITICAL_IMPORTANCE,
+                             0,
+                             0,
+                             0,
+                             0,
+                             subscr_named_msg_event,
+                             0,
+                             0,
+                             &topsrv.setup_port);
+       if (res)
+               goto failed;
+
+       res = nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq);
+       if (res)
+               goto failed;
+
+       spin_unlock_bh(&topsrv.lock);
+       return 0;
+
+failed:
+       err("Failed to create subscription service\n");
+       tipc_detach(topsrv.user_ref);
+       topsrv.user_ref = 0;
+       spin_unlock_bh(&topsrv.lock);
+       return res;
+}
+
+void subscr_stop(void)
+{
+       struct subscriber *subscriber;
+       struct subscriber *subscriber_temp;
+       spinlock_t *subscriber_lock;
+
+       if (topsrv.user_ref) {
+               tipc_deleteport(topsrv.setup_port);
+               list_for_each_entry_safe(subscriber, subscriber_temp, 
+                                        &topsrv.subscriber_list,
+                                        subscriber_list) {
+                       ref_lock(subscriber->ref);
+                       subscriber_lock = subscriber->lock;
+                       subscr_terminate(subscriber);
+                       spin_unlock_bh(subscriber_lock);
+               }
+               tipc_detach(topsrv.user_ref);
+               topsrv.user_ref = 0;
+       }
+}
+
+
+int tipc_ispublished(struct tipc_name const *name)
+{
+       u32 domain = 0;
+
+       return(nametbl_translate(name->type, name->instance,&domain) != 0);
+}
+
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
new file mode 100644 (file)
index 0000000..ccff4ef
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * net/tipc/subscr.h: Include file for TIPC subscription service
+ * 
+ * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_SUBSCR_H
+#define _TIPC_SUBSCR_H
+
+/**
+ * struct subscription - TIPC network topology subscription object
+ * @seq: name sequence associated with subscription
+ * @timeout: duration of subscription (in ms)
+ * @filter: event filtering to be done for subscription
+ * @evt: template for events generated by subscription
+ * @subscription_list: adjacent subscriptions in subscriber's subscription list
+ * @nameseq_list: adjacent subscriptions in name sequence's subscription list
+ * @timer_ref: reference to timer governing subscription duration (may be NULL)
+ * @owner: pointer to subscriber object associated with this subscription
+ */
+struct subscription {
+       struct tipc_name_seq seq;
+       u32 timeout;
+       u32 filter;
+       struct tipc_event evt;
+       struct list_head subscription_list;
+       struct list_head nameseq_list;
+       struct timer_list timer;
+       struct subscriber *owner;
+};
+
+int subscr_overlap(struct subscription * sub, 
+                  u32 found_lower, 
+                  u32 found_upper);
+
+void subscr_report_overlap(struct subscription * sub, 
+                          u32 found_lower, 
+                          u32 found_upper,
+                          u32 event, 
+                          u32 port_ref, 
+                          u32 node,
+                          int must_report);
+
+int subscr_start(void);
+
+void subscr_stop(void);
+
+
+#endif
diff --git a/net/tipc/user_reg.c b/net/tipc/user_reg.c
new file mode 100644 (file)
index 0000000..35ec7dc
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * net/tipc/user_reg.c: TIPC user registry code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2004-2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "user_reg.h"
+
+/*
+ * TIPC user registry keeps track of users of the tipc_port interface.
+ *
+ * The registry utilizes an array of "TIPC user" entries; 
+ * a user's ID is the index of their associated array entry.
+ * Array entry 0 is not used, so userid 0 is not valid;
+ * TIPC sometimes uses this value to denote an anonymous user.
+ * The list of free entries is initially chained from last entry to entry 1.
+ */
+
+/**
+ * struct tipc_user - registered TIPC user info
+ * @next: index of next free registry entry (or -1 for an allocated entry)
+ * @callback: ptr to routine to call when TIPC mode changes (NULL if none)
+ * @usr_handle: user-defined value passed to callback routine 
+ * @ports: list of user ports owned by the user
+ */
+
+struct tipc_user {
+       int next;
+       tipc_mode_event callback;
+       void *usr_handle;
+       struct list_head ports;
+};
+
+#define MAX_USERID 64
+#define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user))
+
+static struct tipc_user *users = 0;
+static u32 next_free_user = MAX_USERID + 1;
+static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * reg_init - create TIPC user registry (but don't activate it)
+ * 
+ * If registry has been pre-initialized it is left "as is".
+ * NOTE: This routine may be called when TIPC is inactive.
+ */
+
+static int reg_init(void)
+{
+       u32 i;
+       
+       spin_lock_bh(&reg_lock);
+       if (!users) {
+               users = (struct tipc_user *)kmalloc(USER_LIST_SIZE, GFP_ATOMIC);
+               if (users) {
+                       memset(users, 0, USER_LIST_SIZE);
+                       for (i = 1; i <= MAX_USERID; i++) {
+                               users[i].next = i - 1;
+                       }
+                       next_free_user = MAX_USERID;
+               }
+       }
+       spin_unlock_bh(&reg_lock);
+       return users ? TIPC_OK : -ENOMEM;
+}
+
+/**
+ * reg_callback - inform TIPC user about current operating mode
+ */
+
+static void reg_callback(struct tipc_user *user_ptr)
+{
+       tipc_mode_event cb;
+       void *arg;
+
+       spin_lock_bh(&reg_lock);
+       cb = user_ptr->callback;
+       arg = user_ptr->usr_handle;
+       spin_unlock_bh(&reg_lock);
+
+       if (cb)
+               cb(arg, tipc_mode, tipc_own_addr);
+}
+
+/**
+ * reg_start - activate TIPC user registry
+ */
+
+int reg_start(void)
+{
+       u32 u;
+       int res;
+
+       if ((res = reg_init()))
+               return res;
+
+       for (u = 1; u <= MAX_USERID; u++) {
+               if (users[u].callback)
+                       k_signal((Handler)reg_callback,
+                                (unsigned long)&users[u]);
+       }
+       return TIPC_OK;
+}
+
+/**
+ * reg_stop - shut down & delete TIPC user registry
+ */
+
+void reg_stop(void)
+{               
+       int id;
+
+       if (!users)
+               return;
+
+       for (id = 1; id <= MAX_USERID; id++) {
+               if (users[id].callback)
+                       reg_callback(&users[id]);
+       }
+       kfree(users);
+       users = 0;
+}
+
+/**
+ * tipc_attach - register a TIPC user
+ *
+ * NOTE: This routine may be called when TIPC is inactive.
+ */
+
+int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle)
+{
+       struct tipc_user *user_ptr;
+
+       if ((tipc_mode == TIPC_NOT_RUNNING) && !cb)
+               return -ENOPROTOOPT;
+       if (!users)
+               reg_init();
+
+       spin_lock_bh(&reg_lock);
+       if (!next_free_user) {
+               spin_unlock_bh(&reg_lock);
+               return -EBUSY;
+       }
+       user_ptr = &users[next_free_user];
+       *userid = next_free_user;
+       next_free_user = user_ptr->next;
+       user_ptr->next = -1; 
+       spin_unlock_bh(&reg_lock);
+
+       user_ptr->callback = cb;
+       user_ptr->usr_handle = usr_handle;
+       INIT_LIST_HEAD(&user_ptr->ports);
+       atomic_inc(&tipc_user_count);
+       
+       if (cb && (tipc_mode != TIPC_NOT_RUNNING))
+               k_signal((Handler)reg_callback, (unsigned long)user_ptr);
+       return TIPC_OK;
+}
+
+/**
+ * tipc_detach - deregister a TIPC user
+ */
+
+void tipc_detach(u32 userid)
+{
+       struct tipc_user *user_ptr;
+       struct list_head ports_temp;
+       struct user_port *up_ptr, *temp_up_ptr;
+
+       if ((userid == 0) || (userid > MAX_USERID))
+               return;
+
+       spin_lock_bh(&reg_lock);
+       if ((!users) || (users[userid].next >= 0)) {
+               spin_unlock_bh(&reg_lock);
+               return;
+       }
+
+       user_ptr = &users[userid];
+        user_ptr->callback = NULL;              
+       INIT_LIST_HEAD(&ports_temp);
+        list_splice(&user_ptr->ports, &ports_temp);
+       user_ptr->next = next_free_user;
+       next_free_user = userid;
+       spin_unlock_bh(&reg_lock);
+
+       atomic_dec(&tipc_user_count);
+
+        list_for_each_entry_safe(up_ptr, temp_up_ptr, &ports_temp, uport_list) {
+               tipc_deleteport(up_ptr->ref);
+       }
+}
+
+/**
+ * reg_add_port - register a user's driver port
+ */
+
+int reg_add_port(struct user_port *up_ptr)
+{
+       struct tipc_user *user_ptr;
+
+       if (up_ptr->user_ref == 0)
+               return TIPC_OK;
+       if (up_ptr->user_ref > MAX_USERID)
+               return -EINVAL;
+       if ((tipc_mode == TIPC_NOT_RUNNING) || !users )
+               return -ENOPROTOOPT;
+
+       spin_lock_bh(&reg_lock);
+       user_ptr = &users[up_ptr->user_ref];
+       list_add(&up_ptr->uport_list, &user_ptr->ports);
+       spin_unlock_bh(&reg_lock);
+       return TIPC_OK;
+}
+
+/**
+ * reg_remove_port - deregister a user's driver port
+ */
+
+int reg_remove_port(struct user_port *up_ptr)
+{
+       if (up_ptr->user_ref == 0)
+               return TIPC_OK;
+       if (up_ptr->user_ref > MAX_USERID)
+               return -EINVAL;
+       if (!users )
+               return -ENOPROTOOPT;
+
+       spin_lock_bh(&reg_lock);
+       list_del_init(&up_ptr->uport_list);
+       spin_unlock_bh(&reg_lock);
+       return TIPC_OK;
+}
+
diff --git a/net/tipc/user_reg.h b/net/tipc/user_reg.h
new file mode 100644 (file)
index 0000000..122ca9b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * net/tipc/user_reg.h: Include file for TIPC user registry code
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_USER_REG_H
+#define _TIPC_USER_REG_H
+
+#include "port.h"
+
+int reg_start(void);
+void reg_stop(void);
+
+int reg_add_port(struct user_port *up_ptr);
+int reg_remove_port(struct user_port *up_ptr);
+
+#endif
diff --git a/net/tipc/zone.c b/net/tipc/zone.c
new file mode 100644 (file)
index 0000000..4eaef66
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * net/tipc/zone.c: TIPC zone management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "zone.h"
+#include "net.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "cluster.h"
+#include "node.h"
+
+struct _zone *zone_create(u32 addr)
+{
+       struct _zone *z_ptr = 0;
+       u32 z_num;
+
+       if (!addr_domain_valid(addr))
+               return 0;
+
+       z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC);
+       if (z_ptr != NULL) {
+               memset(z_ptr, 0, sizeof(*z_ptr));
+               z_num = tipc_zone(addr);
+               z_ptr->addr = tipc_addr(z_num, 0, 0);
+               net.zones[z_num] = z_ptr;
+       }
+       return z_ptr;
+}
+
+void zone_delete(struct _zone *z_ptr)
+{
+       u32 c_num;
+
+       if (!z_ptr)
+               return;
+       for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+               cluster_delete(z_ptr->clusters[c_num]);
+       }
+       kfree(z_ptr);
+}
+
+void zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr)
+{
+       u32 c_num = tipc_cluster(c_ptr->addr);
+
+       assert(c_ptr->addr);
+       assert(c_num <= tipc_max_clusters);
+       assert(z_ptr->clusters[c_num] == 0);
+       z_ptr->clusters[c_num] = c_ptr;
+}
+
+void zone_remove_as_router(struct _zone *z_ptr, u32 router)
+{
+       u32 c_num;
+
+       for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+               if (z_ptr->clusters[c_num]) {
+                       cluster_remove_as_router(z_ptr->clusters[c_num], 
+                                                router);
+               }
+       }
+}
+
+void zone_send_external_routes(struct _zone *z_ptr, u32 dest)
+{
+       u32 c_num;
+
+       for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+               if (z_ptr->clusters[c_num]) {
+                       if (in_own_cluster(z_ptr->addr))
+                               continue;
+                       cluster_send_ext_routes(z_ptr->clusters[c_num], dest);
+               }
+       }
+}
+
+struct node *zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
+{
+       struct cluster *c_ptr;
+       struct node *n_ptr;
+       u32 c_num;
+
+       if (!z_ptr)
+               return 0;
+       c_ptr = z_ptr->clusters[tipc_cluster(addr)];
+       if (!c_ptr)
+               return 0;
+       n_ptr = cluster_select_node(c_ptr, ref);
+       if (n_ptr)
+               return n_ptr;
+
+       /* Links to any other clusters within this zone ? */
+       for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+               c_ptr = z_ptr->clusters[c_num];
+               if (!c_ptr)
+                       return 0;
+               n_ptr = cluster_select_node(c_ptr, ref);
+               if (n_ptr)
+                       return n_ptr;
+       }
+       return 0;
+}
+
+u32 zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref)
+{
+       struct cluster *c_ptr;
+       u32 c_num;
+       u32 router;
+
+       if (!z_ptr)
+               return 0;
+       c_ptr = z_ptr->clusters[tipc_cluster(addr)];
+       router = c_ptr ? cluster_select_router(c_ptr, ref) : 0;
+       if (router)
+               return router;
+
+       /* Links to any other clusters within the zone? */
+       for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
+               c_ptr = z_ptr->clusters[c_num];
+               router = c_ptr ? cluster_select_router(c_ptr, ref) : 0;
+               if (router)
+                       return router;
+       }
+       return 0;
+}
+
+
+u32 zone_next_node(u32 addr)
+{
+       struct cluster *c_ptr = cluster_find(addr);
+
+       if (c_ptr)
+               return cluster_next_node(c_ptr, addr);
+       return 0;
+}
+
diff --git a/net/tipc/zone.h b/net/tipc/zone.h
new file mode 100644 (file)
index 0000000..4326f78
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * net/tipc/zone.h: Include file for TIPC zone management routines
+ * 
+ * Copyright (c) 2000-2006, Ericsson AB
+ * Copyright (c) 2005, Wind River Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_ZONE_H
+#define _TIPC_ZONE_H
+
+#include "node_subscr.h"
+#include "net.h"
+
+
+/**
+ * struct _zone - TIPC zone structure
+ * @addr: network address of zone
+ * @clusters: array of pointers to all clusters within zone
+ * @links: (used for inter-zone communication)
+ */
+struct _zone {
+       u32 addr;
+       struct cluster *clusters[2]; /* currently limited to just 1 cluster */
+       u32 links;
+};
+
+struct node *zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
+u32 zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref);
+void zone_remove_as_router(struct _zone *z_ptr, u32 router);
+void zone_send_external_routes(struct _zone *z_ptr, u32 dest);
+struct _zone *zone_create(u32 addr);
+void zone_delete(struct _zone *z_ptr);
+void zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr);
+u32 zone_next_node(u32 addr);
+
+static inline struct _zone *zone_find(u32 addr)
+{
+       return net.zones[tipc_zone(addr)];
+}
+
+#endif
index 12e4fb72bf0f46bfc22a5e1a8a75efd93792d650..53d6c7bbf56459f6aa7145a7c3649a754588abc1 100644 (file)
@@ -494,8 +494,7 @@ static inline void avc_print_ipv6_addr(struct audit_buffer *ab,
                                       char *name1, char *name2)
 {
        if (!ipv6_addr_any(addr))
-               audit_log_format(ab, " %s=%04x:%04x:%04x:%04x:%04x:"
-                                "%04x:%04x:%04x", name1, NIP6(*addr));
+               audit_log_format(ab, " %s=" NIP6_FMT, name1, NIP6(*addr));
        if (port)
                audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
@@ -504,7 +503,7 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, u32 addr,
                                       __be16 port, char *name1, char *name2)
 {
        if (addr)
-               audit_log_format(ab, " %s=%d.%d.%d.%d", name1, NIPQUAD(addr));
+               audit_log_format(ab, " %s=" NIPQUAD_FMT, name1, NIPQUAD(addr));
        if (port)
                audit_log_format(ab, " %s=%d", name2, ntohs(port));
 }
index 6647204e46366f59917f4779949988e0ad5912c1..b9f8d9731c3d54ba345ef7f2b24c09ffc7cad1ad 100644 (file)
@@ -1019,7 +1019,7 @@ static inline int dentry_has_perm(struct task_struct *tsk,
    has the same SID as the process.  If av is zero, then
    access to the file is not checked, e.g. for cases
    where only the descriptor is affected like seek. */
-static inline int file_has_perm(struct task_struct *tsk,
+static int file_has_perm(struct task_struct *tsk,
                                struct file *file,
                                u32 av)
 {
index a4ecab2f05226255028aa06a7ac26197d848bc20..849b59f67ef57ef18da65b5c161e32f629e788a6 100644 (file)
@@ -515,7 +515,7 @@ static inline int prog_dmabuf_adc(struct solo1_state *s)
        return 0;
 }
 
-static inline int prog_dmabuf_dac(struct solo1_state *s)
+static int prog_dmabuf_dac(struct solo1_state *s)
 {
        unsigned long va;
        int c;
index 9ffb600321cbb78ffdedd4ebcf9f61e3e6dcb6b6..3747a436f0cd2028d22f772bedf756fe95ca08dd 100644 (file)
@@ -727,7 +727,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
        apu_data_set(chip, data);
 }
 
-static inline void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
+static void apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 data)
 {
        unsigned long flags;
        spin_lock_irqsave(&chip->reg_lock, flags);
@@ -743,7 +743,7 @@ static u16 __apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
        return __maestro_read(chip, IDR0_DATA_PORT);
 }
 
-static inline u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
+static u16 apu_get_register(struct es1968 *chip, u16 channel, u8 reg)
 {
        unsigned long flags;
        u16 v;